Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding check box values to list in the model mvc

My problem is I have to create a layout like the following Using MVC to assign rights to the user.Sample of the lay out needed

Now there is no problem in creating the check boxes I'll create it using the list of users. but while submitting the form i should submit it to the list like below.

public class UserRightsViewModel
    {
       public UserRightsViewModel()
        {
            _screenrights = new List<ScreenRight>();

        }
        public String Id { get; set; }// Role Name 
        List<ScreenRight> _screenrights;
        public List<ScreenRight> ScreenRights { get { return _screenrights; } set { _screenrights = value; } }

    }

definition for screenRight is below

public class ScreenRight
{
       public String UserName { get; set; }
        public Boolean Select{ get; set; }
        public Boolean Add{ get; set; }
        public Boolean Edit{ get; set; }
       ,,,
}

Now while submitting the form how can i post it to the controller in the right format.

like image 881
user1811801 Avatar asked Dec 11 '22 20:12

user1811801


2 Answers

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new UserRightsViewModel
        {
            // Obviously those could come from some data source
            ScreenRights = new[]
            {
                new ScreenRight { UserName = "Robert", Select = true, Add = false, Edit = false },
                new ScreenRight { UserName = "John", Select = true, Add = true, Edit = false },
                new ScreenRight { UserName = "Mike", Select = true, Add = true, Edit = false },
                new ScreenRight { UserName = "Allan", Select = true, Add = true, Edit = true },
                new ScreenRight { UserName = "Richard", Select = false, Add = false, Edit = false },
            }.ToList()
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(UserRightsViewModel model)
    {
        // The view model will be correctly populated here
        // TODO: do some processing with them and redirect or
        // render the same view passing it the view model
        ...
    }
}

View:

@model UserRightsViewModel

@using (Html.BeginForm())
{
    <table>    
        <thead>
            <tr>
                <th>User Id</th>
                <th>Select</th>
                <th>Add</th>
                <th>Edit</th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.ScreenRights.Count; i++)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(x => x.ScreenRights[i].UserName)
                        @Html.HiddenFor(x => x.ScreenRights[i].UserName)
                    </td>
                    <td>
                        @Html.CheckBoxFor(x => x.ScreenRights[i].Select)
                    </td>
                    <td>
                        @Html.CheckBoxFor(x => x.ScreenRights[i].Add)
                    </td>
                    <td>
                        @Html.CheckBoxFor(x => x.ScreenRights[i].Edit)
                    </td>
                </tr>
            }
        </tbody>
    </table>

    <button type="submit">OK</button>
}

Further reading: Model Binding To a List.

like image 188
Darin Dimitrov Avatar answered Jan 08 '23 12:01

Darin Dimitrov


To work backwards, your eventual HTML should look like this (ignoring your table)

<input type="hidden" value="0" name="ScreenRights[0].Select"/>  
<input type="checkbox"  name="ScreenRights[0].Select"/>

<input type="hidden" value="0" name="ScreenRights[0].Add"/>  
<input type="checkbox" name="ScreenRights[0].Add"/>

<input type="hidden" value="0" name="ScreenRights[0].Edit"/> 
<input type="checkbox" name="ScreenRights[0].Edit"/>

<input type="hidden" value="0" name="ScreenRights[1].Select"/>  
<input type="checkbox"  name="ScreenRights[1].Select"/>

<input type="hidden" value="0" name="ScreenRights[1].Add"/>  
<input type="checkbox"  name="ScreenRights[1].Add"/>

<input type="hidden" value="0" name="ScreenRights[1].Edit"/> 
<input type="checkbox"  name="ScreenRights[1].Edit"/>

The idea is that the index order shows up in the [i] array portion of the property name, and then chain into the next property. It should bind up in the same order as your i's. The other key here is the check boxes only bind up with CHECKED attribute, so value has no meaning in terms of the binder. That's why you have the hidden input in front. The binder will always assign false, and then override to true if the checkbox is checked. You can verify this resulting html with Html.CheckBoxFor on a simple model.

In terms of getting your HTML to look like that, you can do it manually, or you can make use of the built-in framework.

I'm pretty sure you can just do this in a for Loop (i as the iterator)

@Html.CheckBoxFor(m => m.ScreenRights[i].Select)
@Html.CheckBoxFor(m => m.ScreenRights[i].Add)
@Html.CheckBoxFor(m => m.ScreenRights[i].Add)
like image 30
Adam Avatar answered Jan 08 '23 12:01

Adam