I'm trying to create a dynamic form in Blazor but I'm stuck. I have a FormFactory component that takes two input parameters. Model for my data binding and a dictionary that defines which elements should be created. The idea is to pass a model object
public class Data
{
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
}
and a dictionary
{ "Name": "string" },
{ "Phone": "string" }
I want to create a form with two input fields for Name and Phone bound to the properties in my model.
<h3>Dynamic form</h3>
<EditForm Model="@DataContext">
@foreach (var field in FieldIdentifiers)
{
if (field.Value == "string")
{
<InputText @bind-Value="DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString()"></InputText>
}
}
</EditForm>
@code {
[Parameter] public object DataContext { get; set; }
[Parameter] public Dictionary<string, string> FieldIdentifiers { get; set; }
}
But this doesn't work. I get an error saying
"Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type" and "The left hnad side of an assignment must be a variable, property or indexer"
EDIT: I've found that Blazor generates a ValueChanged attribute that causes error
builder2.AddAttribute(8, "ValueChanged", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<Microsoft.AspNetCore.Components.EventCallback<System.String>>(Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(this, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, __value => DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString() = __value, DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString()))));
That won't work so I tried creating a RenderFragment and changed my component as following
<h3>Dynamic form</h3>
@MyForm()
@code {
[Parameter] public object DataContext { get; set; }
[Parameter] public Dictionary<string, string> FieldIdentifiers { get; set; }
RenderFragment MyForm() => builder =>
{
builder.AddMarkupContent(0, "<h3>Dynamic form</h3>\r\n");
builder.OpenComponent<Microsoft.AspNetCore.Components.Forms.EditForm>(1);
builder.AddAttribute(2, "Model", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Object>(DataContext));
builder.AddAttribute(3, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment<Microsoft.AspNetCore.Components.Forms.EditContext>)((context) => builder2 =>
{
builder2.AddMarkupContent(4, "\r\n");
foreach (var field in FieldIdentifiers)
{
if (field.Value == "string")
{
builder2.AddContent(5, " ");
builder2.OpenComponent<Microsoft.AspNetCore.Components.Forms.InputText>(6);
builder2.AddAttribute(7, "Value", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.String>(Microsoft.AspNetCore.Components.BindMethods.GetValue(DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString())));
builder2.AddAttribute(8, "ValueChanged", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<Microsoft.AspNetCore.Components.EventCallback<System.String>>(Microsoft.AspNetCore.Components.EventCallback.Factory.Create<System.String>(this, Microsoft.AspNetCore.Components.EventCallback.Factory.CreateInferred(this, __value => DataContext.GetType().GetProperty(field.Key).SetValue(DataContext, __value), DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null).ToString()))));
builder2.AddAttribute(9, "ValueExpression", Microsoft.AspNetCore.Components.RuntimeHelpers.TypeCheck<System.Linq.Expressions.Expression<System.Func<System.String>>>(() => Convert.ToString(DataContext.GetType().GetProperty(field.Key).GetValue(DataContext, null))));
builder2.CloseComponent();
builder2.AddMarkupContent(10, "\r\n");
}
}
builder2.AddMarkupContent(11, "\r\n");
}));
builder.CloseComponent();
};
}
This compiles but I get a runtime error
System.ArgumentException: The provided expression contains a MethodCallExpression1 which is not supported. FieldIdentifier only supports > simple member accessors (fields, properties) of an object.
Any help would be appreciated