I can not get a Blazor EditForm with complex objects to work.
Here's an example of a simple Dice Roller, where the user can select the amount of dices and dice types he wants to roll. When Submitting the form, the formData variable is always null.
What am I doing wrong?
@using DiceMaster.Lib.Dices
@using System.ComponentModel
<EditForm Enhance Model="@formData" OnValidSubmit="@RollDices" FormName="DiceRoller">
@foreach (var am in formData.Amounts)
{
<InputSelect @bind-Value="am.DiceTypeId">
@foreach (DiceType ty in diceTypeGetter.GetDiceTypes())
{
<option value="@ty.TypeId">@ty.Name</option>
}
</InputSelect>
<InputNumber @bind-Value="am.DiceCount" min="1" max="1000000"></InputNumber>
}
<button type="submit">Roll</button>
</EditForm>
@if (rollResults.Count > 0)
{
foreach (DiceRollResult result in rollResults.OrderBy(r=>r.DiceTypeId).ThenBy(r=>r.SortIndex))
{
<div>@result.Value</div>
}
}
@code {
[SupplyParameterFromForm]
public RoleDiceFormInfo formData { get; set; }
private DiceTypeGetter diceTypeGetter { get; set; } = new DiceTypeGetter();
private List<DiceRollResult> rollResults { get; set; } = new List<DiceRollResult>();
protected override void OnInitialized()
{
if (formData is null)
{
formData = new() {Amounts = new List<DiceTypeAmmount>()
{
new DiceTypeAmmount()
{
DiceCount = 1, DiceTypeId = diceTypeGetter.GetDiceTypes().First(d=>d.Name == "D6").TypeId
},new DiceTypeAmmount()
{
DiceCount = 1,DiceTypeId = diceTypeGetter.GetDiceTypes().First(d=>d.Name == "D3").TypeId
}
}};
}
}
private void RollDices()
{
DiceRoller roller = new DiceRoller();
DiceRollRequest request = new DiceRollRequest();
request.DiceAmmounts = new List<DiceTypeAmmount>();
request.DiceAmmounts.AddRange(formData.Amounts);
List<DiceRollResult> results = roller.RollDices(request);
rollResults = results;
}
public class RoleDiceFormInfo
{
public List<DiceTypeAmmount> Amounts { get; set; }
}
public class DiceTypeAmmount()
{
public Guid DiceTypeId { get; set; }
public int DiceCount { get; set; }
}
}
I expect the formData model to bind correctly
the name of the select would be rendered as am.DiceTypeId:
However,in static ssr ,model binding would perform as MVC/RazorPage,you could check this document for more details
requires the name to be rendered as
formData.Amounts[index].DiceCount
I tried to modify the name attribute with InputSelect/InputNumber component ,but both failed whatever in for loop /foreach loop
If you would accept dropping InputSelect/InputNumber
component,the codes below would work for you:
@{
int index = 0;
}
@foreach (var am in formData.Amounts)
{
<select name="formData.Amounts[@index].DiceTypeId" @bind="@formData.Amounts[@index].DiceTypeId">
//I don't know the codes in your GetDiceTypes() method
<option value="@Guid.NewGuid()">Type1</option>
<option value="@Guid.NewGuid()">Type2</option>
</select>
<input type="number" name="formData.Amounts[@index].DiceCount" @bind="@formData.Amounts[@index].DiceCount" min="1" max="1000000">
index++;
}
It would work on myside: