Blazor GenericEditForm

83 views Asked by At

i dont know if this is relevant to write here.

I want to create a GenericEditForm.razor which can be used on multiple pages.

I currently have made the GenericEditForm component so that it takes a @typeparam TModel which can be different kinds of Models. I also give it a json config, where i have specified something i call "render definitions". There is a json config for each of my possible models that i would want to create a GenericEditForm for. In the json config i have a list of ojbects times the properties of my model

My problem is that i cant find a way to use the @bind-value og @bind to bind the different form controls to the models properties, given that the GenericEditForm components only knows the model and its properties at runtime.

Any ideas of how to fix this, using data binding.

JSON CONFIG:

{
  "CreateTitle": "Create new committee",
  "Fields": [
    {
      "ModelPropName": "Department",
      "DisplayName": "Department",
      "FormControlType": "InputSelect",
      "Items": [
        "Afdeling A",
        "Afdeling B",
        "Afdeling C"
      ],
      "Rules": {
        "Mandatory": true,
        "Regex": "[a-zA-Z0-9.,_ åæøÅÆØ-]{0,100}"
      }
    },
    {
      "ModelPropName": "CommitteeName",
      "DisplayName": "Committee name",
      "FormControlType": "InputText",
      "Rules": {
        "Mandatory": true,
        "regex": "[a-zA-Z0-9.,_ åæøÅÆØ-]{0,100}"
      }
    },
    {
      "ModelPropName": "Status",
      "DisplayName": "Status",
      "FormControlType": "InputSelect",
      "Items": [
        "Status 1",
        "Status 2"
      ],
      "Rules": {
        "Mandatory": true,
        "regex": ""
      }
    }
  ]
}

GenericEditForm:

 @foreach (var field in FormControlConfig.Fields)
                        {
                            var propertyName = field.ModelPropName;
                            var propertyInfo = typeof(TItem).GetProperty(propertyName);
                            var propertyValue = GetPropertyValue(propertyInfo);
                            switch (field.FormControlType)
                            {
                                case "InputText":
                                    <EditFormControlWrapper FieldName="@field.DisplayName" IsRequired="@field.Rules.Mandatory">
                                        <div class="col-xs-17 col-sm-12 col-md-10 col-lg-11">
                                            <input type="text"
                                   spellcheck="true"
                                   class="form-control"
                                   id="@propertyName"
                                   value="@propertyValue"
                                   @oninput="e => SetValue(e.Value, propertyInfo)">
                                        </div>
                                    </EditFormControlWrapper>
                                    break;
                                case "InputSelect":
                                    @if (field.DisplayName == "Status")
                                    {
                                        break;
                                    }
                                    <EditFormControlWrapper FieldName="@field.DisplayName" IsRequired="@field.Rules.Mandatory" isSelect="true">
                                        <div class="col-xs-17 col-sm-12 col-md-10 col-lg-11 select">
                                            <select class="form-control"
                                    id="@propertyName"
                                    value="@propertyValue"
                                    @oninput="e => SetValue(e.Value, propertyInfo)">
                                                <option value="" />
                                                @foreach (var item in field.Items)
                                                {
                                                    <option value="@item">@item</option>
                                                }
                                            </select>
                                        </div>
                                    </EditFormControlWrapper>
                                    break;
                                case "InputTextArea":
                                    <EditFormControlWrapper FieldName="@field.DisplayName" IsRequired="@field.Rules.Mandatory">
                                        <div class="col-xs-17 col-sm-12 col-md-10 col-lg-11">
                                            <textarea cols="20"
                                      rows="4"
                                      type="text"
                                      spellcheck="true"
                                      class="form-control"
                                      id="@propertyName"
                                      value="@propertyValue"
                                      @oninput="e => SetValue(e.Value, propertyInfo)" />
                                        </div>
                                    </EditFormControlWrapper>
                                    break;
                                case "InputDate":
                                    <EditFormControlWrapper FieldName="@field.DisplayName" IsRequired="@field.Rules.Mandatory">
                                        <div class="col-xs-17 col-sm-7 col-md-10 col-lg-3">
                                            <input type="date"
                                   class="form-control datepicker hasDatepicker"
                                   value="@Convert.ToString(propertyValue)"
                                   @oninput="e => SetValue(DateTime.Parse(e.Value.ToString()), propertyInfo)" />
                                        </div>
                                    </EditFormControlWrapper>
                                    break;
                                case "InputTime":
                                    var startName = "MeetingTimeStart";
                                    var endName = "MeetingTimeEnd";
                                    var propertyInfoStart = typeof(TItem).GetProperty(startName);
                                    var propertyInfoEnd = typeof(TItem).GetProperty(endName);
                                    var startValue = GetPropertyValue(propertyInfoStart);
                                    var endValue = GetPropertyValue(propertyInfoEnd);

                                    <EditFormControlWrapper FieldName="@field.DisplayName" IsRequired="@field.Rules.Mandatory">
                                        <div class="col-xs-17 col-sm-7 col-md-10 col-lg-2 select">
                                            <select class="form-control"
                                    min="09:00" max="18:00"
                                    size="1"
                                    id="@startName"
                                    value="@Convert.ToString(startValue)"
                                    @oninput="e => SetValue(TimeSpan.Parse(e.Value.ToString()), propertyInfoStart)">
                                                @for (int hour = 9; hour <= 18; hour++)
                                                {
                                                    @for (int minute = 0; minute < 60; minute += 15)
                                                    {
                                                        var timeSpan = new TimeSpan(hour, minute, 0);
                                                        var timeString = timeSpan.ToString(@"hh\:mm");
                                                        <option value="@timeSpan">@timeString</option>
                                                    }
                                                }
                                            </select>
                                        </div>
                                        <div class="col-lg-0">
                                            <label class="control-label">
                                                :
                                            </label>
                                        </div>
                                        <div class="col-xs-17 col-sm-7 col-md-10 col-lg-2 select">
                                            <select class="form-control"
                                    min="09:00" max="18:00"
                                    size="1"
                                    id="@endName"
                                    value="@Convert.ToString(endValue)"
                                    @oninput="e => SetValue(TimeSpan.Parse(e.Value.ToString()), propertyInfoEnd)">
                                                @for (int hour = 9; hour <= 18; hour++)
                                                {
                                                    @for (int minute = 0; minute < 60; minute += 15)
                                                    {
                                                        var timeSpan = new TimeSpan(hour, minute, 0);
                                                        var timeString = timeSpan.ToString(@"hh\:mm");
                                                        <option value="@timeSpan">@timeString</option>
                                                    }
                                                }
                                            </select>
                                        </div>
                                    </EditFormControlWrapper>
                                    break;
                            }
                        }
    
@code {
 [Parameter]
    public ProfileFormControlConfigModel FormControlConfig { get; set; }

    [Parameter]
    public object? EditObject { get; set; }

    public TItem CreateModel;

    public bool hasStatusField = false;

    public bool isActive = false;

    public Field field;

    protected override async Task OnParametersSetAsync()
    {
        try
        {
            CreateModel = Activator.CreateInstance<TItem>();

            var result = CreateModel.GetType().GetProperty("Status");

        if (result != null) { hasStatusField = true; }
        }
        catch (ArgumentNullException ex)
        {
            // Handle ArgumentNullException related to the GetProperty() method
            Console.WriteLine("Error: Property name is null.");
        }
        catch (AmbiguousMatchException ex)
        {
            // Handle AmbiguousMatchException related to the GetProperty() method
            Console.WriteLine("Error: More than one property with the specified name found.");
        }
        catch (Exception ex)
        {
            // Handle any other exception
            Console.WriteLine("Error: " + ex.Message);
        }
 public void SetValue(object value, PropertyInfo propertyInfo)
    {
        Type propType = propertyInfo.PropertyType;
        propertyInfo.SetValue(CreateModel, value);
    }

    private object GetPropertyValue(PropertyInfo propertyInfo)
    {
        Type propType = propertyInfo.PropertyType;

        object propertyValue;

        propertyValue = propertyInfo.GetValue(CreateModel);
        
        return propertyValue;
    }
}

0

There are 0 answers