Kevin Lee
Kevin Lee

Reputation: 1135

ASP.NET MVC cannot POST view model with binding to checkbox

Here are my view models:

public class UserViewModel
{
    public User GroupUser { get; set; }
    public bool Checked { get; set; }
}

public class GroupUserViewModel
{
    public Guid GroupId { get; set; }
    public string GroupName { get; set; }
    public IList<UserViewModel> Users;        
}

My view:

@model GroupUserViewModel

@{
    ViewBag.Title = "Users";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>@Model.GroupName</h2>

@using (Html.BeginForm("AddUserToGroup", "Group", FormMethod.Post))
{
    for (var userIter = 0; userIter < Model.Users.Count(); userIter++)
    {
        <div class="form-group">
            @Html.DisplayFor(model => model.Users[userIter].GroupUser.UserName)
            @Html.CheckBoxFor(model => model.Users[userIter].Checked)

            @Html.HiddenFor(model => model.GroupId)
            @Html.HiddenFor(model => model.GroupName)
        </div>        
    }

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

My controller:

[HttpPost]
public ActionResult AddUserToGroup(GroupUserViewModel groupUsers)
{
    //do things    
}

I had an inspection of the POST data and it is:

Users[0].Checked=true
Users[0].Checked=false
Users[1].Checked=false

For the boxes I've ticked there are 2 entries, one true and one false. Is this normal?

Also in the controller, what I get back is:

groupUsers.GroupId = {00000000-0000-0000-0000-000000000000}
groupUsers.GroupName = null
groupUsers.Users = null

Obviously since the form isn't actually posting the view model I want back to the controller, this happens. Is there any way to pass the required view model back to the controller since I need the GroupId and GroupName?

EDIT:

After some updates and adding in hidden fields for GroupId and GroupName, now the POST data is:

Users[0].Checked=true
Users[0].Checked=false
Id=015f5aef-eb6c-449e-9f08-9d42110c5347
GroupName=MyName
MyObjects[1].Checked=false
Id=015f5aef-eb6c-449e-9f08-9d42110c5347
GroupName=MyName

The GroupId and GroupName are now being passed corrently but the list is still null.

Upvotes: 1

Views: 1581

Answers (2)

user3559349
user3559349

Reputation:

IList<UserViewModel> Users in GroupUserViewModel is a field, not a property so the DefaultModelBinder cannot set its value. Change it to

public class GroupUserViewModel
{
    ....
    public IList<UserViewModel> Users { get; set; } // make it a property   
}

Upvotes: 1

user844705
user844705

Reputation:

Yes this is normal. The reason is because an unchecked checkbox will not post a value, so ASP.NET renders a hidden field for every checkbox with the same ID as the checkbox just after the checkbox control, and sets its value to false. ASP.NET DefaultModelBinder will, if there are multiple form fields with the same name, take the first value. This results in one value of false being posted from the hidden field if the checkbox is not checked, and two values, one of false for the hidden field and one of true for the checked checkbox. Because the hidden field comes after the checkbox, if the checkbox posts a value, it will override the hidden field. However, that doesn't answer your question as to why the model isn't binding..

Upvotes: 4

Related Questions