I am following this blog Editing a variable length list, ASP.NET MVC 2-style by Steven Anderson and started using Html.BeginCollectionItem() for my ASP.NET MVC project.

The project is about associating multiple permissions to roles. It will have a Role page(view) where user will have option to add permissions by selecting one of the permissions from drop-down list. User will also be able to add these permissions drop-down list by clicking on 'Add' button. 'Add' would dynamically add new drop-down list control on the page. Remove would remove the last drop-down list.

The issue I am facing is with binding nested collection. I have used RolePermissions list below which inturn is a list of RolePermissionViewModel.

See below for screenshots.

Role

Permissions

Role Controller: I have hardcoded sample data for testing.

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using MUtilities.Model.Entities;
using MUtilities.Web.Areas.Admin.Models;
using MUtilities.Web.Controllers;
using HtmlHelpers.BeginCollectionItem;
namespace MUtilities.Web.Areas.Admin.Controllers
{
    public class RoleController : BaseController
    {
        public ActionResult Index()
        {


            return View();
        }


        public ViewResult BlankPermission()
        {
            return View("_PermissionPartial", GetPermissions());
        }
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            var role = MRepository.AllRoles.Find(id);
            if (role == null)
            {
                return HttpNotFound();
            }
            return View(role);
        }


        private List<List<RolePermissionViewModel>> GetPermissionList() {           
            var rolePermissions = new List<List<RolePermissionViewModel>>();
            rolePermissions.Add(GetPermissions());
            rolePermissions.Add(GetPermissions());
            return rolePermissions;
        }
        private List<RolePermissionViewModel> GetPermissions()
        {
            var permissions = new List<RolePermissionViewModel>();
          permissions.Add(new RolePermissionViewModel
        {
            PermissionId = -1,
            PermissionName = "--Select a Permission--"
         });
            permissions.Add(new RolePermissionViewModel
            {
                PermissionId = 1,
                PermissionName = "Create of Utility1"
            });
            permissions.Add(new RolePermissionViewModel
            {
                PermissionId = 2,
                PermissionName = "Update of of Utility1"
            });
            return permissions;
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "Id,Name,Description,RolePermissions")] RoleViewModel roleModel)
        {

            if (ModelState.IsValid)
            {
                var role = new Role();
                role.Name = roleModel.Name;

            //some logic here

                return RedirectToAction("Index");
            }

            return View();
        }

        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            //some logic to edit view
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,Name,Permissions")] RoleViewModel roleModel)
        {
            if (ModelState.IsValid)
            {
                var role = MRepository.AllRoles.First(r => r.Id == roleModel.Id);
                role.Name = roleModel.Name;

               //some logic to commit 

                return RedirectToAction("Index");
            }
            return View();
        }

        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Role role = MRepository.AllRoles.Find(id);
            if (role == null)
            {
                return HttpNotFound();
            }
            return View(role);
        }

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            var role = MRepository.AllRoles.Find(id);
            MRepositoryAllRoles.Remove(role);
            MRepository.Commit();
            return RedirectToAction("Index");
        }
    }
}

Role View:

@model MUtilities.Web.Areas.Admin.Models.RoleViewModel

@{
    ViewBag.Title = "Create";
}
@section scripts{
 <script type="text/javascript">
        $(function () {
            $("#addPermissionBtn").click(function () {
                $.ajax({
                    url: this.href,
                    cache: false,
                    success: function (html) {
                        $("#addPermissionDdl").append(html);
                        //The call to Sys.Mvc.FormContext._Application_Load() refreshes 
                        //the validation on the page to include the new fields.
                        Sys.Mvc.FormContext._Application_Load();
                    }
                });
                return false;
            });

            $("#deletePermissionBtn").on("click", function () {
                var pDdls = $("select[id$='__PermissionList']");
                if (pDdls && pDdls.length > 1) {
                    pDdls.last().remove();
                    //$(this).parents("div.addPermissionDdl:last").remove();
                }
                return false;
            });
        });

</script>   
}
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Role</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RolePermissions, htmlAttributes: new { @class = "control-label col-md-2" })

            @using (Html.BeginForm())
            {
                <div id="addPermissionDdl" class="col-md-10">
                    @foreach (var rolePermission in Model.RolePermissions)
                    {
                        Html.RenderPartial("_PermissionPartial", rolePermission);
                    }


                </div>
                <div class="col-md-10">
                    @Html.ActionLink("Add", "BlankPermission", null, new { id = "addPermissionBtn", @class = "glyphicon glyphicon-plus-sign" })
                    <a href="#" id="deletePermissionBtn" class="glyphicon glyphicon-remove-circle">Delete</a>
                    </div>
                }
                </div>


        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

RoleViewModel: RolePermissions is a list of RolePermissionViewModel list.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace MUtilities.Web.Areas.Admin.Models
{
    public class RoleViewModel
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }

        public string Description { get; set; }

        [Display(Name="Permissions")]
        public List<List<RolePermissionViewModel>> RolePermissions { get; set; }
    }

    public class RolePermissionViewModel
    {
        public int PermissionId { get; set; }
        public string PermissionName { get; set; }

    }
}

_PermissionPartial.cshtml

 @{
        Layout = null;
    }

    @using HtmlHelpers.BeginCollectionItem;
    @model IEnumerable<MUtilities.Web.Areas.Admin.Models.RolePermissionViewModel>

    @using (Html.BeginCollectionItem("RolePermissions"))
    {
        var permissionDdl = new SelectList(Model.Select(m => m), "PermissionId", "PermissionName", "--Select a Permission--");

        @Html.DropDownList("PermissionList", permissionDdl, new { @class = "form-control" });

    }

But when I click Create button Name, Description would bind ok but not the Permissions. See below.

RolePermission_Not_Binding

Any idea what might be happening?

Related posts

Recent Viewed