2

I've seen the other threads on the subject, but am having trouble with what I believe is the correct syntax/setup. Ultimately the controller is not able to see the contents of the Role list when it is being returned from an edit.

View

@model Models.Volunteer

            @foreach (var item in Model.Roles)
            {
                <input type="checkbox" asp-for="@item.Selected" />
                <label asp-for="@item.Selected">@item.RoleName</label>
                <input type="hidden" asp-for="@item.RoleId" />
                <input type="hidden" asp-for="@item.RoleName" />
                <br />
            }

<input type="submit" value="Save" class="btn btn-default" />

Model

public abstract class BaseVolunteer
{
    [Key]
    public int Recno { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string City { get; set; }
    [NotMapped]
    [Display(Name = "Roles")]
    public List<Role> Roles { get; set; }
}

public class Role
{
    [Key]
    public String RoleId { get; set; }
    public String RoleName { get; set; }

    public bool Selected { get; set; }
}

Controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("Recno,FirstName,LastName,Email,City,Roles")] Volunteer volunteer)
    {
}

The volunteer object in the controller correctly returns the other values... but the Roles object is NULL despite being properly populated for display.

1 Answer 1

6

You need to use the array-indexer so the model-binder knows the index of each item:

@for( Int32 i = 0; i < this.Model.Roles.Length; i++ ) {
    <input type="checkbox" asp-for="@Model.Roles[i].Selected" />
    <label asp-for="@Model.Roles[i].Selected">@Model.Roles[i].RoleName</label>
    <input type="hidden" asp-for="@Model.Roles[i].RoleId" />
    <input type="hidden" asp-for="@Model.Roles[i].RoleName" />
    <br />
} 

This will be rendered into something like this:

    <input type="checkbox" name="Roles[0].Selected" value="false" id="Roles_0__Selected" />
    <label for="Roles_0__Selected">Admin</label>
    <input type="hidden" name="Roles[0].RoleId" value="10" />
    <input type="hidden" name="Roles[0].RoleName" value="Admin" />
    <br />

    <input type="checkbox" name="Roles[1].Selected" value="false" id="Roles_1__Selected" />
    <label for="Roles_1__Selected">Users</label>
    <input type="hidden" name="Roles[1].RoleId" value="120" />
    <input type="hidden" name="Roles[1].RoleName" value="Users" />
    <br />

    <input type="checkbox" name="Roles[2].Selected" value="false" id="Roles_2__Selected" />
    <label for="Roles_2__Selected">Guests</label>
    <input type="hidden" name="Roles[2].RoleId" value="123" />
    <input type="hidden" name="Roles[2].RoleName" value="Guestsd />
    <br />

Notice how the name="" values contain the index which the Model binder can use.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I'm obviously new to .NET core... but this makes me wonder why they support the foreach syntax if the model binder doesn't recognize it properly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.