Creating a matrix of checkboxes which supports post back in ASP.NET MVC

别说谁变了你拦得住时间么 提交于 2019-12-23 03:44:10

问题


I'm trying to think of a way to manage the selection of a matrix of values via view models in MVC 5.

I have a list of companies and a list of roles. The roles are the same for each company. What I want is to output a matrix of companies/roles with a checkbox for each combination. This allows the user to select which role the person will have for each company.

I can render the output with nested foreach loops but I can't help but think there's a better way to achieve this with MVC and Editor Templates.

Below is a crude example of the layout. So every company is output as a column and every role is output as a row. A checkbox for each company is then output into every row.

Company/Role  COMPANY1 COMPANY2 COMPANY3
ROLE1            [X]       []      []
ROLE2            []        []      [X]   
ROLE3            []        []      []

The added complexity is being able to handle postback. My view model structure is currently..

public class RequestViewModel
    {
        public Guid Id { get; set; }
        public List<CompanyAccessViewModel> CompanyAccessViewModels { get; set; }
    }

public class CompanyAccessViewModel
    {
        public int Company { get; set; }
        public Guid Id { get; set; }
        public Guid RequestId { get; set; }
        public List<Company> ListCompanies { get; set; }
        public List<Role> ListRoles { get; set; }
        public List<CompanyAccessRoleViewModel> CompanyAccessRoleViewModels { get; set; }
    }

public class CompanyAccessRoleViewModel
    {
        public Guid AccessRequirementId { get; set; }
        public Guid Id { get; set; }
        public string Role { get; set; }
    }

ListCompanies is the list of all the companies. ListRoles is a list of all the roles.


回答1:


As always, start with a view model(s) to represent what you want to display/edit.

public class RoleVM
{
    public int ID { get; set; }
    public string Name { get; set; }
    public List<CompanyVM> Companies { get; set; }
}
public class CompanyVM
{
    public int ID { get; set; }
    public string Name { get; set; }
    public bool IsSelected { get; set; }
}

and in the GET method

[HttpGet]
public ActionResult Index()
{
    IEnumerable<Role> roles = db.Roles;
    IEnumerable<Company> companies = db.Companies;
    List<RoleVM> model = roles.Select(x => new RoleVM()
    {
        ID = x.ID,
        Name = x.Name,
        Companies = companies.Select(y => new CompanyVM()
        {
            ID = y.ID,
            Name = y.Name
        }).ToList()
    }).ToList();
    // For editing existing roles, set the IsSelected property
    // of the respective CompanyVM to true
    return View(model);
}

and the view

@model List<RoleVM>
@using (Html.BeginForm())
{
    <table>
        <thead>
            <tr>
                <th>Company/Role</th>
                @foreach(var company in Model.FirstOrDefault().Companies)
                {
                    <th>@company.Name</th>
                }
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Count; i++)
            {
                <tr>
                    <td>
                        @Model[i].Name
                        @Html.HiddenFor(m => m[i].ID)
                        @Html.HiddenFor(m => m[i].Name)
                    </td>
                    @for (int j = 0; j < Model[i].Companies.Count; j++)
                    {
                        <td>
                            @Html.HiddenFor(m => m[i].Companies[j].ID)
                            @Html.HiddenFor(m => m[i].Companies[j].Name)
                            @Html.CheckBoxFor(m => m[i].Companies[j].IsSelected)
                        </td>
                    }
                </tr>
            }
        </tbody>
    </table>    
    <button type="submit">Save</button>
}

which will the post to

[HttpPost]
public ActionResult Index(List<RoleVM> model)
{
    // To get the companies for each role
    foreach (var role in model)
    {
        var selectedCompanies = role.Companies.Where(x => x.IsSelected);

Note that using nested foreach loops would never have bound correctly when submitting your form (you need to use for loops). If you want to use EditorTemplates (your properties can be IEnumerable<T> rather that IList<T>, then create a partial in /Views/Shared/EditorTemplates/RoleVM.cshtml

@model RoleVM
<tr>
    <td>
        @Model.Name
        @Html.HiddenFor(m => m.ID)
        @Html.HiddenFor(m => m.Name)
    </td>
    @Html.EditorFor(m => m.Companies)
</tr>

and another for /Views/Shared/EditorTemplates/CompanyVM.cshtml

@model CompanyVM
<td>
     @Html.HiddenFor(m => m.ID)
     @Html.HiddenFor(m => m.Name)
     @Html.CheckBoxFor(m => m.IsSelected)
</td>

and the main view would be

@model List<RoleVM>
.... // as above
<tbody>
    @Html.EditorFor(m => m)
</tbody>


来源:https://stackoverflow.com/questions/37729936/creating-a-matrix-of-checkboxes-which-supports-post-back-in-asp-net-mvc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!