I am creating a large html form (using the EditForm tag) in my Blazor WASM app, containing many properties. Mostly all of which follow an identical pattern of a label, an input, and a validation section. I would like to create a render fragment that would let me cut down on my mark up. I am struggling with how to reference the "bind-Value" for the correct property.
Here is the start of the edit form, which has a model called registerModel with many properties, including string "Company" representing "Company Name"
<EditForm autocomplete="off" Model="@registerModel" OnValidSubmit="@HandleValidRegisterSubmit">
This is an example of a single section for the company name part, of which there are many in the form for all the individual properties:
<div class="row mb-3 align-items-center">
<div class="col-sm-2">
<label>
Company Name
</label>
</div>
<div class="col-sm-6 p-0">
<InputText @bind-Value="registerModel.Company" type="text" placeholder="Enter Company Name"
class="rounded-input form-control"
id="Last"
autocomplete="off"/>
</div>
<div class="col-sm-4">
<ValidationMessage For="() => registerModel.Company"/>
</div>
</div>
I want a render fragment function to automate creating each form section so I don't have to repeat so much html, and I can make my component more reusable. This is what I have tried so far
RenderFragment<(
EventCallback<string> eventCallback,
Expression<Func<string>> func,
string id,
string label,
string placeholder)> RenderFieldSection = (item) => __builder =>
{
<div class="row mb-3 align-items-center">
<div class="col-sm-2">
<label>@item.label</label>
</div>
<div class="col-sm-6 p-0">
<InputText @bind-Value="@item.eventCallback" type="text" placeholder="@item.placeholder"
class="rounded-input form-control"
id="@item.id"
autocomplete="off"/>
</div>
<div class="col-sm-4">
<ValidationMessage For="@item.func"/>
</div>
</div>
};
Which I am trying to call in the markup with:
@RenderFieldSection((
eventCallback: EventCallback.Factory.Create<string>(this, s => { registerModel.Company = s;}),
func:()=> registerModel.Company,
id: "Company",
label:Translate("CompanyNameLabel"),
placeholder:Translate("CompanyNamePlaceholder")
)
)
Everything works except the input @bind-Value="@item.eventCallback" part, which is supposed to take an EventCallback<string>. This gives the following error.
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
I guess I am constructing the event callback wrongly, but I don't know how to do it. Any ideas? I expect I could do it by finding the property via reflection, but I (naively?) wonder if I can avoid the overhead of that.