diff --git a/src/FormBuilder/Components/FieldPropertyEditor.razor b/src/FormBuilder/Components/FieldPropertyEditor.razor index bc4aa2b..aea7082 100644 --- a/src/FormBuilder/Components/FieldPropertyEditor.razor +++ b/src/FormBuilder/Components/FieldPropertyEditor.razor @@ -33,20 +33,13 @@ - @if (Field is TextField textField) - { - - - - } - @if (Field is NumericField numericIntField) { - + } @if (Field is NumericField numericDecimalField) { - + } @if (Field is DateField dateField) @@ -83,7 +76,7 @@ } } - - + + } diff --git a/src/FormBuilder/Components/FieldValidatorsEditor.razor b/src/FormBuilder/Components/FieldValidatorsEditor.razor new file mode 100644 index 0000000..7374997 --- /dev/null +++ b/src/FormBuilder/Components/FieldValidatorsEditor.razor @@ -0,0 +1,60 @@ +@using FormBuilder.Models + + + + + @switch (Field.Type) + { + case FieldType.Text: + + + break; + case FieldType.NumericInt or FieldType.NumericDecimal: + + break; + } + + + + + + @foreach (var validator in Field.Validators) + { + @switch (validator) + { + case RequiredValidator requiredValidator: + + + + break; + case EmailValidator emailValidator: + + + + break; + case LengthValidator lengthValidator: + + + + break; + case NumericRangeValidator numericRangeValidator: + + + + break; + } + } + + diff --git a/src/FormBuilder/Components/FieldValidatorsEditor.razor.cs b/src/FormBuilder/Components/FieldValidatorsEditor.razor.cs new file mode 100644 index 0000000..3d5bfdc --- /dev/null +++ b/src/FormBuilder/Components/FieldValidatorsEditor.razor.cs @@ -0,0 +1,29 @@ +using FormBuilder.Factories; +using FormBuilder.Models; +using Microsoft.AspNetCore.Components; + +namespace FormBuilder.Components; + +public partial class FieldValidatorsEditor : ComponentBase +{ + #region Parameters + + [Parameter, EditorRequired] + public Field Field { get; set; } = default!; + + [Parameter] + public EventCallback FieldChanged { get; set; } + + #endregion + + private void RaiseFieldChanged() + { + FieldChanged.InvokeAsync(Field); + } + + private void AddValidator(ValidatorType validatorType) + { + Field.Validators.Add(ValidatorFactory.Create(validatorType)); + FieldChanged.InvokeAsync(Field); + } +} diff --git a/src/FormBuilder/Components/FormEditor.razor b/src/FormBuilder/Components/FormEditor.razor index 8708313..d8e4f30 100644 --- a/src/FormBuilder/Components/FormEditor.razor +++ b/src/FormBuilder/Components/FormEditor.razor @@ -1,7 +1,7 @@ @using FormBuilder.Models - + @if (_formDefinition.Id is not null) { @@ -47,10 +47,10 @@ - + - + @@ -79,12 +79,13 @@ } - @if (_formDefinition.Fields.Count > 0) - { - - } - - + + @if (_formDefinition.Fields.Count > 0) + { + + } + + diff --git a/src/FormBuilder/Components/FormEditor.razor.cs b/src/FormBuilder/Components/FormEditor.razor.cs index 44cf00d..532803c 100644 --- a/src/FormBuilder/Components/FormEditor.razor.cs +++ b/src/FormBuilder/Components/FormEditor.razor.cs @@ -74,7 +74,7 @@ private async Task UpdateFormDesignJsonAsync() private Task AddField(FieldType fieldType) { - var field = FieldFactory.CreateField(fieldType); + var field = FieldFactory.Create(fieldType); field.Label = fieldType.ToString(); _formDefinition.Fields.Add(field); SelectedField = field; @@ -106,7 +106,7 @@ private Task HandleFieldPropertyChanged(FieldPropertyChangedArgs args) /// private void ChangeFieldType(FieldType newType, Field oldField) { - var newField = FieldFactory.CreateFieldFrom(newType, oldField); + var newField = FieldFactory.CreateFrom(newType, oldField); var index = _formDefinition.Fields.IndexOf(oldField); _formDefinition.Fields[index] = newField; // Replace the old field with the new one, old one will be deleted by GC SelectedField = newField; diff --git a/src/FormBuilder/Components/FormField.razor b/src/FormBuilder/Components/FormField.razor index 09968d1..604e807 100644 --- a/src/FormBuilder/Components/FormField.razor +++ b/src/FormBuilder/Components/FormField.razor @@ -10,7 +10,7 @@ Name="@textField.Name" @bind-Value="textField.Value" Placeholder="@textField.Placeholder" - MaxLength="@textField.MaxLength" + MaxLength="@textField.GetMaxLength()" ReadOnly="Disabled"> break; @@ -28,8 +28,8 @@ Name="@numericIntField.Name" @bind-Value="numericIntField.Value" Placeholder="@numericIntField.Placeholder" - Min="numericIntField.Min" - Max="numericIntField.Max" + Min="numericIntField.GetMin()" + Max="numericIntField.GetMax()" ShowUpDown="numericIntField.ShowUpDown" Step="@numericIntField.Step" Format="@numericIntField.Format" @@ -41,8 +41,8 @@ Name="@numericField.Name" @bind-Value="numericField.Value" Placeholder="@numericField.Placeholder" - Min="numericField.Min" - Max="numericField.Max" + Min="numericField.GetMin()" + Max="numericField.GetMax()" ShowUpDown="numericField.ShowUpDown" Step="@numericField.Step" Format="@numericField.Format" @@ -100,7 +100,7 @@ Text="@lengthValidator.Text"> break; - case RangeValidator rangeValidator: + case NumericRangeValidator rangeValidator: - - - - - diff --git a/src/FormBuilder/Components/NumericFieldPropertyEditor.razor.cs b/src/FormBuilder/Components/NumericFieldEditor.razor.cs similarity index 66% rename from src/FormBuilder/Components/NumericFieldPropertyEditor.razor.cs rename to src/FormBuilder/Components/NumericFieldEditor.razor.cs index 4a2afb8..e62b83c 100644 --- a/src/FormBuilder/Components/NumericFieldPropertyEditor.razor.cs +++ b/src/FormBuilder/Components/NumericFieldEditor.razor.cs @@ -3,7 +3,7 @@ namespace FormBuilder.Components; -public partial class NumericFieldPropertyEditor : ComponentBase where TValue : struct +public partial class NumericFieldEditor : ComponentBase where TValue : struct { [Parameter, EditorRequired] public NumericField Field { get; set; } = default!; @@ -11,18 +11,6 @@ public partial class NumericFieldPropertyEditor : ComponentBase where TV [Parameter] public EventCallback> FieldChanged { get; set; } - private void OnMinChanged(decimal? value) - { - Field.Min = value; - FieldChanged.InvokeAsync(Field); - } - - private void OnMaxChanged(decimal? value) - { - Field.Max = value; - FieldChanged.InvokeAsync(Field); - } - private void OnStepChanged(string value) { Field.Step = value; diff --git a/src/FormBuilder/Components/ValidatorPropertyEditor.razor b/src/FormBuilder/Components/ValidatorPropertyEditor.razor new file mode 100644 index 0000000..a9e8bdd --- /dev/null +++ b/src/FormBuilder/Components/ValidatorPropertyEditor.razor @@ -0,0 +1,42 @@ +@using FormBuilder.Models +@typeparam TValue where TValue : FormBuilder.Models.Validator + + + + + + + + + + + @switch (Validator) + { + case RequiredValidator requiredValidator: + + + + + + + + + break; + case LengthValidator lengthValidator: + + + + + + + break; + case NumericRangeValidator numericRangeValidator: + + + + + + + break; + } + diff --git a/src/FormBuilder/Components/ValidatorPropertyEditor.razor.cs b/src/FormBuilder/Components/ValidatorPropertyEditor.razor.cs new file mode 100644 index 0000000..39f294d --- /dev/null +++ b/src/FormBuilder/Components/ValidatorPropertyEditor.razor.cs @@ -0,0 +1,74 @@ +using FormBuilder.Models; +using Microsoft.AspNetCore.Components; + +namespace FormBuilder.Components; + +public partial class ValidatorPropertyEditor : ComponentBase where TValue : Validator +{ + #region Parameters + + [Parameter, EditorRequired] + public TValue Validator { get; set; } = default!; + + [Parameter] + public EventCallback ValidatorChanged { get; set; } + + #endregion + + private void OnTextChanged(string value) + { + Validator.Text = value; + ValidatorChanged.InvokeAsync(Validator); + } + + private void OnShowAsPopupChanged(bool value) + { + Validator.ShowAsPopup = value; + ValidatorChanged.InvokeAsync(Validator); + } + + private void OnShowRequiredHintChanged(bool value) + { + if (Validator is RequiredValidator requiredValidator) + { + requiredValidator.ShowRequiredHint = value; + ValidatorChanged.InvokeAsync(Validator); + } + } + + private void OnMinLengthChanged(int? value) + { + if (Validator is LengthValidator lengthValidator) + { + lengthValidator.MinLength = value; + ValidatorChanged.InvokeAsync(Validator); + } + } + + private void OnMaxLengthChanged(int? value) + { + if (Validator is LengthValidator lengthValidator) + { + lengthValidator.MaxLength = value; + ValidatorChanged.InvokeAsync(Validator); + } + } + + private void OnMinChanged(int value) + { + if (Validator is NumericRangeValidator numericRangeValidator) + { + numericRangeValidator.Min = value; + ValidatorChanged.InvokeAsync(Validator); + } + } + + private void OnMaxChanged(int value) + { + if (Validator is NumericRangeValidator numericRangeValidator) + { + numericRangeValidator.Max = value; + ValidatorChanged.InvokeAsync(Validator); + } + } +} diff --git a/src/FormBuilder/Converters/ValidatorJsonConverter.cs b/src/FormBuilder/Converters/ValidatorJsonConverter.cs index 9638655..79c776e 100644 --- a/src/FormBuilder/Converters/ValidatorJsonConverter.cs +++ b/src/FormBuilder/Converters/ValidatorJsonConverter.cs @@ -28,7 +28,7 @@ public override Validator Read(ref Utf8JsonReader reader, Type typeToConvert, Js ValidatorType.Required => JsonSerializer.Deserialize(rootElement.GetRawText(), options), ValidatorType.Length => JsonSerializer.Deserialize(rootElement.GetRawText(), options), ValidatorType.Email => JsonSerializer.Deserialize(rootElement.GetRawText(), options), - ValidatorType.Range => JsonSerializer.Deserialize(rootElement.GetRawText(), options), + ValidatorType.NumericRange => JsonSerializer.Deserialize(rootElement.GetRawText(), options), _ => throw new NotSupportedException($"The value of the validator type '{enumValidatorType}' is not supported"), }; diff --git a/src/FormBuilder/Factories/FieldFactory.cs b/src/FormBuilder/Factories/FieldFactory.cs index c88a3c9..1a83b68 100644 --- a/src/FormBuilder/Factories/FieldFactory.cs +++ b/src/FormBuilder/Factories/FieldFactory.cs @@ -9,13 +9,13 @@ public static class FieldFactory { /// /// Creates a new field model based on the provided fieldType. - /// List of available field types: TextField, NumericIntField, NumericDoubleField, SelectField, DateField. + /// List of available field types: TextField, NumericIntField, NumericDecimalField, SelectField, DateField. /// /// The type of the field to create. /// /// A generic instance of the field based on the provided fieldType. /// - public static Field CreateField(FieldType fieldType) + public static Field Create(FieldType fieldType) { return fieldType switch { @@ -36,9 +36,9 @@ public static Field CreateField(FieldType fieldType) /// /// A generic instance of the field based on the provided fieldType. /// - public static Field CreateFieldFrom(FieldType newFieldType, Field oldField) + public static Field CreateFrom(FieldType newFieldType, Field oldField) { - var newField = CreateField(newFieldType); + var newField = Create(newFieldType); newField.Label = oldField.Label; newField.Placeholder = oldField.Placeholder; newField.ReadOnly = oldField.ReadOnly; diff --git a/src/FormBuilder/Factories/ValidatorFactory.cs b/src/FormBuilder/Factories/ValidatorFactory.cs new file mode 100644 index 0000000..491ae5a --- /dev/null +++ b/src/FormBuilder/Factories/ValidatorFactory.cs @@ -0,0 +1,33 @@ +using FormBuilder.Models; + +namespace FormBuilder.Factories; + +/// +/// Factory class for creating validators. +/// +public static class ValidatorFactory +{ + /// + /// Creates a validator based on the given type. + /// + /// + /// The type of the validator to create. + /// + /// + /// A new instance of the validator based on the provided type. + /// + /// + /// Thrown when the provided validator type is not recognized. + /// + public static Validator Create(ValidatorType validatorType) + { + return validatorType switch + { + ValidatorType.Required => new RequiredValidator(), + ValidatorType.Length => new LengthValidator(), + ValidatorType.Email => new EmailValidator(), + ValidatorType.NumericRange => new NumericRangeValidator(), + _ => throw new ArgumentOutOfRangeException(nameof(validatorType), validatorType, null) + }; + } +} diff --git a/src/FormBuilder/Models/DateField.cs b/src/FormBuilder/Models/Fields/DateField.cs similarity index 100% rename from src/FormBuilder/Models/DateField.cs rename to src/FormBuilder/Models/Fields/DateField.cs diff --git a/src/FormBuilder/Models/Field.cs b/src/FormBuilder/Models/Fields/Field.cs similarity index 100% rename from src/FormBuilder/Models/Field.cs rename to src/FormBuilder/Models/Fields/Field.cs diff --git a/src/FormBuilder/Models/FieldType.cs b/src/FormBuilder/Models/Fields/FieldType.cs similarity index 100% rename from src/FormBuilder/Models/FieldType.cs rename to src/FormBuilder/Models/Fields/FieldType.cs diff --git a/src/FormBuilder/Models/NumericField.cs b/src/FormBuilder/Models/Fields/NumericField.cs similarity index 78% rename from src/FormBuilder/Models/NumericField.cs rename to src/FormBuilder/Models/Fields/NumericField.cs index 2f710e6..dbedf37 100644 --- a/src/FormBuilder/Models/NumericField.cs +++ b/src/FormBuilder/Models/Fields/NumericField.cs @@ -11,7 +11,6 @@ public NumericField() else if (typeof(T) == typeof(uint) || typeof(T) == typeof(ulong) || typeof(T) == typeof(ushort)) { Type = FieldType.NumericInt; - Min = 0; } else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(double) || typeof(T) == typeof(float)) { @@ -24,9 +23,17 @@ public NumericField() } public override FieldType Type { get; } - public decimal? Min { get; set; } - public decimal? Max { get; set; } public string Step { get; set; } = "1"; public bool ShowUpDown { get; set; } = true; public string? Format { get; set; } + + public decimal? GetMin() + { + return Validators.OfType().FirstOrDefault()?.Min; + } + + public decimal? GetMax() + { + return Validators.OfType().FirstOrDefault()?.Max; + } } diff --git a/src/FormBuilder/Models/SelectField.cs b/src/FormBuilder/Models/Fields/SelectField.cs similarity index 100% rename from src/FormBuilder/Models/SelectField.cs rename to src/FormBuilder/Models/Fields/SelectField.cs diff --git a/src/FormBuilder/Models/TextField.cs b/src/FormBuilder/Models/Fields/TextField.cs similarity index 50% rename from src/FormBuilder/Models/TextField.cs rename to src/FormBuilder/Models/Fields/TextField.cs index b6da344..1900988 100644 --- a/src/FormBuilder/Models/TextField.cs +++ b/src/FormBuilder/Models/Fields/TextField.cs @@ -3,5 +3,9 @@ public class TextField : Field { public override FieldType Type => FieldType.Text; - public long? MaxLength { get; set; } + + public long? GetMaxLength() + { + return Validators.OfType().FirstOrDefault()?.MaxLength; + } } diff --git a/src/FormBuilder/Models/ValidatorType.cs b/src/FormBuilder/Models/ValidatorType.cs deleted file mode 100644 index 39f4681..0000000 --- a/src/FormBuilder/Models/ValidatorType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace FormBuilder.Models; - -public enum ValidatorType -{ - Required = 1, - Length = 2, - Email = 3, - Range = 4, -} diff --git a/src/FormBuilder/Models/EmailValidator.cs b/src/FormBuilder/Models/Validators/EmailValidator.cs similarity index 100% rename from src/FormBuilder/Models/EmailValidator.cs rename to src/FormBuilder/Models/Validators/EmailValidator.cs diff --git a/src/FormBuilder/Models/LengthValidator.cs b/src/FormBuilder/Models/Validators/LengthValidator.cs similarity index 100% rename from src/FormBuilder/Models/LengthValidator.cs rename to src/FormBuilder/Models/Validators/LengthValidator.cs diff --git a/src/FormBuilder/Models/NumericRangeValidator.cs b/src/FormBuilder/Models/Validators/NumericRangeValidator.cs similarity index 60% rename from src/FormBuilder/Models/NumericRangeValidator.cs rename to src/FormBuilder/Models/Validators/NumericRangeValidator.cs index 883f704..de8c8c9 100644 --- a/src/FormBuilder/Models/NumericRangeValidator.cs +++ b/src/FormBuilder/Models/Validators/NumericRangeValidator.cs @@ -1,8 +1,8 @@ namespace FormBuilder.Models; -public class RangeValidator : Validator +public class NumericRangeValidator : Validator { - public override ValidatorType Type => ValidatorType.Range; + public override ValidatorType Type => ValidatorType.NumericRange; public override string Text { get; set; } = "Not in the valid range"; public int Min { get; set; } public int Max { get; set; } diff --git a/src/FormBuilder/Models/RequiredValidator.cs b/src/FormBuilder/Models/Validators/RequiredValidator.cs similarity index 100% rename from src/FormBuilder/Models/RequiredValidator.cs rename to src/FormBuilder/Models/Validators/RequiredValidator.cs diff --git a/src/FormBuilder/Models/Validator.cs b/src/FormBuilder/Models/Validators/Validator.cs similarity index 100% rename from src/FormBuilder/Models/Validator.cs rename to src/FormBuilder/Models/Validators/Validator.cs diff --git a/src/FormBuilder/Models/Validators/ValidatorType.cs b/src/FormBuilder/Models/Validators/ValidatorType.cs new file mode 100644 index 0000000..70a7955 --- /dev/null +++ b/src/FormBuilder/Models/Validators/ValidatorType.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; + +namespace FormBuilder.Models; + +public enum ValidatorType +{ + [Description("Required Validator")] + Required = 1, + + [Description("Length Validator")] + Length = 2, + + [Description("Email Validator")] + Email = 3, + + [Description("Numeric Range Validator")] + NumericRange = 4, +}