4
votes

I'm trying to generate forms with Blazor programatically, and I'm running into an issue where I need to bind an InputText value to a memeber of a collection such as:

@foreach (var prop in formProperties)
{
    <InputText [email protected] @bind-Value="form.Responses[prop.Name]" />
}

However, I get the following exception:

System.ArgumentException: The provided expression contains a InstanceMethodCallExpression1 which is not supported. FieldIdentifier only supports simple member accessors (fields, properties) of an object.

Is it possible to bind input to a collection of some sort?

2
Yes, create a component that takes (binds) the formProperties. Then create a child component that takes prop. The parent component foreach's through the collection and renders a child component for each prop. The child component can then handle the rendering of the correct <InputText> fields for each property of prop and bind them. - Dennis v. W.
Where would the <InputText> fields be binded to? And how could I get that data to the parent? - Adam
Using Component-to-Component Data Binding. Blazor provides two-way data binding between components called Chained Bind Through an eventcallback and by using the naming convention propertyChanged you can notify the parent on updates. - Dennis v. W.

2 Answers

6
votes

Running into a similar issue where I'm trying to build a table based on a dictionary of attributes, I came across this reply from Steve.

Basically what you can do is introduce a new type called e.g.

public class FormResponse
{
    public string Value { get; set;
}

Assuming you now create a dictionary of FormResponse on your form object, you can then do this:

@foreach (var prop in formProperties)
{
    <InputText id="@prop.Name" @bind-Value="form.Responses[prop.Name].Value" />
}

Which is arguably more straightforward than creating a new component with Chained Binding.

0
votes

Unfortunately, you cannot use the <InputText/> component for more complex accessors presently.

However, if you don't mind handling your own validation/notification code, you can roll your own by:

  • Changing the <InputText/> to an <input/>
  • Use @bind instead of @bind-Value

Using your code:

@foreach (var prop in formProperties)
{
    <input [email protected] @bind="form.Responses[prop.Name]" />
}

Again, you will loose change notifications, and validation, and all connection to the EditForm and EditContext.

You can also go the route that @dennis1679 suggested, creating a sub component. I am curious what the Chained Binding integration with the top level form/model validation would be like in practice with. I haven't played with that yet.

FYI, I did a quick search, and didn't see the issue (likely a feature) in github, but when I find it, I will update this.