0

I am very new to MVC, and I am trying to achieve the following.

I have view where I am displaying a dropdown list for roles. On selected index change of this drop-down list. I display the name of pages and a check box in front of each page name. The checkboxes are checked if the role has permission to access that page. Now I want to edit the permission the Role has, by checking/unchecking the checkboxes and saving on update button click.

Screen shot of my View

So far, I have done the following.

View Model

public class PagesViewModel
{
    public int PageID { get; set; }
    public string PageTitle { get; set; }
    public string SectionName { get; set; }
    public bool IsSelected { get; set; }
}
 public class RoleViewModel
{
    public int RoleID { get; set; }
    public string RoleName { get; set; }
    public List<PagesViewModel> pages { get; set; }
}

My Controller

    public ActionResult Index()
    {
        RoleViewModel _RolePriv = new RoleViewModel();
        _RolePriv.RoleID = 0;
        _RolePriv.RoleName = "";
        _RolePriv.pages = GetPages();
        GetRoles(0);
        return View(_RolePriv);
    }

    [HttpPost]
    public ActionResult GetPrivilege(RoleViewModel rolePriv)
    {
        AdminRole role = new AdminRole();
        string joined = string.Join(",", rolePriv.pages.Where(x => 
        x.IsSelected == true).Select(x => x.PageID));
        role = db.AdminRoles.Where(c => c.ID == rolePriv.RoleID).Single();
        role.ID = rolePriv.RoleID;
        role.AdminPrivilege = joined;
        db.AdminRoles.Attach(role);
        //db.Entry(role).State = System.Data.Entity.EntityState.Modified;
        db.SaveChanges();

        return RedirectToAction("Index"); 
    }

    [HttpGet]
    public ActionResult GetPrivilege(int ID)
    {

        GetRoles(ID);
        if (ID != 0)
        {
             RoleViewModel _RolePriv = new RoleViewModel();
            _RolePriv.RoleID = ID;
            _RolePriv.RoleName = (from r in db.AdminRoles
                             where r.ID == ID
                             select r.Name).FirstOrDefault();

            var privilege = (from r in db.AdminRoles
                             where r.ID == ID
                             select r.AdminPrivilege).FirstOrDefault();

        List<int> PageIds = 
       privilege.Split(';').Select(int.Parse).ToList();
      List<PagesViewModel> _menus = db.AdminPages.OrderBy(x => 
      x.ViewOrder)
     .Where(x => x.Parent==0 &&                                                               
      x.PageLevel==0 && 
                                x.Active == 1)
       .Select(x => new PagesViewModel{                                                          
        PageID = x.ID,                                            
        PageTitle = x.Title,                                                                
        SectionName = x.AdminSection.Name,                                                                
        IsSelected = (                                                                
        PageIds.Contains(x.ID) ? true : false)
                                                        }).ToList();

                        _RolePriv.pages = _menus;
                        return View("Index", _RolePriv);
        }

        return RedirectToAction("Index"); 

    }

    public List<PagesViewModel> GetPages()
    {
        List<PagesViewModel> _menus1 = db.AdminPages.OrderBy(x => 
        x.ViewOrder)                                                           
      .Where(x => x.Parent == 0 &&                                                                   
             x.PageLevel == 0 &&                                                                   
             x.Active == 1)                                                           
         .Select(x => new PagesViewModel                                                           
            {                                                               
           PageID = x.ID,                                                               
           PageTitle = x.Title,                                                               
           SectionName = x.AdminSection.Name,                                                                
           IsSelected = false                                                           
           }).ToList();
        return _menus1;
    }


    public void GetRoles(int ID)
    {
        List<SelectListItem> roleList = new List<SelectListItem>();
        roleList = db.AdminRoles.ToList().Select(x => new SelectListItem
        {
            Value = x.ID.ToString(),
            Text = x.Name
        }).ToList();

          roleList.Insert(0, new SelectListItem { Text = "-Select Role-", 
           Value = "0" });

        ViewBag.RoleList = new SelectList(roleList, "Value", "Text", ID);
       }

    }
 }

  My View

   @model MvcMPark.ViewModel.RoleViewModel
    @{
         ViewBag.Title = "Index";
         Layout = "~/Views/Shared/_Layout.cshtml";
    }

   <p >
       @Html.Label("Edit Privilege")
   </p>

  @using (Html.BeginForm())
  {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)


   @Html.DropDownList("RoleList1", (SelectList)ViewBag.RoleList,new { 
       onchange = "document.location.href = 
      'http://localhost:61628/RolePrivilege/GetPrivilege/' + 
        this.options[this.selectedIndex].value;",  
      style="display:block;"})

@Html.HiddenFor(m => m.RoleID)
@Html.DisplayFor(m => m.RoleName, new { style="diaplay:block;"})


 <ul>
    @for (int i = 0; i < Model.pages.Count; i++)
    {
        <li style="clear:both;">
                @Html.HiddenFor(m => m.pages[i].PageID)
                 @Html.CheckBoxFor(m => m.pages[i].IsSelected, new { 
                 style="float:left;margin:5px;"})
                 @Html.LabelFor(m => m.pages[i].IsSelected, 
                 Model.pages[i].PageTitle, new { style="float:left;"})
         </li>
    }
</ul>


    <p>
        <input type="submit" value="Update"/>
    </p>
   }
  1. I want the view to be
Section1
     page1
     page2

Section2
     page3
     page4

but now it is coming like this

  page1
  page2
  page3
  page4

How to bring it in the way I want

  1. On submit button click the below action is called, the values inside the object is correct but it does not get saved to the Role by db.SaveChanges();
[HttpPost]
    public ActionResult GetPrivilege(RoleViewModel rolePriv)

So what is the correct way to call an action on submit button click so that a new function “SetPrivilege” is called and not GetPrivilege and also why are my values not getting saved

  • Please be more specific in tags, add for example `ASP` or `WinForm` or `WPF` so we know what platform you are using – horotab Sep 12 '18 at 09:40
  • How can you pass viewmodel properties to `List` (by using AJAX or normal form submit)? Where is your `
    ` tag/`Html.BeginForm()` and why using `foreach` for checkboxes?
    – Tetsuya Yamamoto Sep 12 '18 at 09:45
  • @TetsuyaYamamoto
    tag/Html.BeginForm() is there but while posting here the code was not getting properly formatted to I removed from here. I dont know can you please advice what is wrong and how should I do it
    – user2398932 Sep 12 '18 at 09:52
  • You cannot use a `foreach` loop to generate form controls for a collection. And your `@Html.CheckBox(SubMenuList.Title,SubMenuList.Selected, ..)` makes no sense and does not compile anyway. Refer [Post an HTML Table to ADO.NET DataTable](https://stackoverflow.com/questions/30094047/post-an-html-table-to-ado-net-datatable/30094943#30094943) –  Sep 12 '18 at 10:09
  • And you do not redirect in an `onchange` event (you have a separate button to make the redirect) - and in any case, what do you thing will happen when you publish your app with that hard coded url that points to `localhost` –  Sep 12 '18 at 10:12
  • I have edited the question and added an Image for more clear description. The code is working gets the permission (Page ID comma separated) saved in the db for a particular role and displays the checkbox checked as per that. but I am unable to save the new permissions – user2398932 Sep 12 '18 at 10:28
  • Read the link I gave you! (and then look at the html you are generating for the checkbox to understand why that can never bind to anything) –  Sep 12 '18 at 10:33
  • And also refer [Pass List of Checkboxes into View and Pull out IEnumerable](https://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416) for how to do this correctly –  Sep 12 '18 at 10:34
  • @ Stephen Muecke I will make the changes as per your suggestion and then post my question again. Thanks for the advise. – user2398932 Sep 12 '18 at 10:55
  • @StephenMuecke I have made all the changes as per your suggestion and edited my Post as per my changes. I am still not able to get the desired result. Please advice – user2398932 Sep 16 '18 at 09:50
  • If you want to group by 'Section'. Then you need `RoleViewModel` needs a property `List Sections` where `SectionViewModel` contains properties `string SectionName` and `List Pages` (and `PagesViewModel`does not contain `string SectionName`). And then you will have nested `for` loops (or better use an `EditorTemplate` for `SectionViewModel` and `PagesViewModel`). –  Sep 18 '18 at 06:27
  • @Stephen Muecke Thanks to you.. its working fine now. :) – user2398932 Sep 19 '18 at 06:30
  • @Stephen Muecke you said I should not be redirecting on an On Change Event then what should I do to load the current permissions from the DB based on selected role. although its working fine.. but is there a better way – user2398932 Sep 19 '18 at 12:37
  • Allow the user to make there selection and then click a button to redirect (you can simply have a form with the dropdownlist that makes a GET to your `GetPrivilege` method). Consider users who use the keyboard to navigate through the options - they want to select the 4th one, but you redirect them as soon as they navigate to the first one –  Sep 19 '18 at 12:47

0 Answers0