0

My code has undergone an incredible change in order to make mutlitple checkboxes work. I did away with the formsCollection I was trying to use to loop through checked checkboxes on the View. I am using a lot of loops inside of loops both in Controller and in View and I don't care anymore about "separation of concerns" or anything modern about MVC. In MS Access you can lump a whole bunch of functions into one line which makes it unreadable but works. I always spread out the logic in order to understand it and step through it. I am probably using a sophomoric approach to this new modern world of MVC 6 but I don't care. I can move on out of the Roles crap into actually doing something with CRUD. I also don't want to piss Stephen Muecke off at all since most of my MVC knowledge is a compilation of his attention to my questions. After Googling it with Bing I found this link about checkboxes that was very simple and helpful. And most of my view was already set up. My time was spent on displaying the user's roles that were already checked. So now, I have a View and an Edit form that allows adding or removing Roles for selected user via checkboxes. Not pretty but very tasty IMHO. ("MVC6" is the name of my project, not a built in name). I did not have to use Owin dependencies. Only dependentcy I had to add was to enable session so I could send TempData["Status"] message. Everything else is right out of the "box".

View:

    @using MVC6.Models
    @using Microsoft.AspNet.Http
    @model Microsoft.AspNet.Identity.EntityFramework.IdentityUser

    @{
        ViewBag.Title = "Edit User";

        var roles = new MVC6Context().Roles.ToList();
        var usersroles = new MVC6Context().UserRoles.ToList();



    }
    <ol class="breadcrumb">
        <li>@Html.ActionLink("Administration", "Index", "Admin")</li>
        <li>@Html.ActionLink("Users", "Index", "UserManagement")</li>
        <li>Edit User</li>
    </ol>

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

        @Html.HiddenFor(model => model.Id)
        @Html.HiddenFor(model => model.Email)
        <h3>Username:</h3>
        <div class="form-control">
            @Model.Email
        </div>

        <h3>Roles:</h3>

        if (roles.Any())
        {
            <div >
                @foreach (var role in roles)
                {
                    bool isinrole = false;

                    @foreach (var ur in usersroles)
                    {
                      @if (Model.Id == ur.UserId) //usersroles returns all roles for all users
                     {
                        @if(ur.RoleId == role.Id)
                        {
                            isinrole = true;
                        }
                      }
                    }

                    @if (isinrole)
                    {
                        <input type="checkbox" name="checkRoles" value="@role.Name" checked />
                        @Html.Label(role.Name)
                    }
                    else
                    {

                        <input type="checkbox" name="checkRoles" value="@role.Name"/>
                        @Html.Label(role.Name)


                    }

                    <br/>
                }
            </div>
            <br />
            <button type="submit" class="btn btn-default">Save</button> <span style="color:red;">@if (@TempData["Status"] != null){@TempData["Status"]}</span>
        }
        else
        {
            <div class="alert alert-info" role="alert">
                No roles available
            </div>
        }
        <br />

Controller

        [HttpGet]
        public ActionResult Edit(string userId)
        {
            return View(context.Users.FirstOrDefault(u => u.Id == userId));
        }

        [HttpPost]
        public async Task<ActionResult> Edit(string[] checkRoles, string userID)
        {

            var UserManager = _serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
            var RoleManager = _serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
            var allRoles = RoleManager.Roles.ToList();
            var user = await UserManager.FindByIdAsync(userID);           
            var usersRoles = await UserManager.GetRolesAsync(user);

            //LOOP THROUGH ROLES
            foreach (var item in allRoles)
            {
                bool wasChecked = false;
                //ALL CHECKBOXES THAT WERE CHECKED
                foreach (var roleChecked in checkRoles)
                {
                    if (item.Name == roleChecked)
                    {
                        wasChecked = true;
                    }
                }

                //ALL CHECKBOXES THAT WERE NOT CHECKED
                if (wasChecked == false)
                {
                    //IF USER HAS ROLE, REMOVE IT
                    if (await UserManager.IsInRoleAsync(user, item.Name))
                    {
                        await UserManager.RemoveFromRoleAsync(user, item.Name);
                    }
                }
                else     //IF CHECK BOX CHECKED THEN ADD ROLE TO USER
                {
                    await UserManager.AddToRoleAsync(user, item.Name);
                }

            }

            TempData["Status"] = "Roles are updated as of <b>" + DateTime.Now.ToShortTimeString() + "</b>";

            return View(user);

        }

What might help another newbie like me is that the AspNetUserRoles table has 2 columns, UserId and RuleId. This is a "many-to-many" relationship. In my code above once I get all the info about the user I want to edit, and get all the user's roles from this many-to-many, then I can iterate through it to add or delete a row. Kinda same thing for the View. I know this stuff could be refactored but it is doing business as we talk. I would gladly give accepted answer to someone who even slightly refactors this (but doesn't turn it into mad scientist gobbly gook, all due respect).

JustJohn
  • 1,362
  • 2
  • 22
  • 44
  • Do not use `FormCollection` Use a view model and strongly bind to your model - for example [this answer](http://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416) –  Jan 15 '16 at 00:30
  • Oh man. I was hoping for a reason why nothing was in the FormsCollection hack I was doing. The MVC 5 code I am upgrading to MVC 6 does see the forms collection and does loop through and add the role(s). I was just trying to add one role from the forms collection. So. . . I've bookmarked your example and when I have cleared my mind and taken a ton of B-Complex I will assimilate it. thank you – JustJohn Jan 15 '16 at 00:45
  • Ok, rebuilding from scratch using your way. I made the ViewModel and in the Edit ActionResult I have the user and the roles but I don't know how to map properties to the ViewModel as per your commented text: // Get you User based on the ID and map properties to the ViewModel // including populating the Roles and setting their IsSelect property // based on existing roles – JustJohn Jan 15 '16 at 01:37
  • In that example, `IEnumerable selectedRoles = model.Roles.Where(r => r.IsSelected).Select(r => r.Name);` would give you the names of selected roles. So in your case you would want something like `foreach(string role in selectedRoles) { RoleAddToUser(user.Id, role); }` –  Jan 15 '16 at 01:51
  • Thanks for the attention yet I haven't even figured out how to populate the ViewModel with User and Roles AND . .. .include which ones are selected: – JustJohn Jan 15 '16 at 02:07
  • `model.Roles = roles.Select(r => new RoleVM{ ID = r.ID, Name = r.Name });` will add all available roles. Then if you editing and existing user, you can loop through the users roles and find the corresponding RoleVM and set the `IsSelected` property to true. –  Jan 15 '16 at 02:19
  • I'm going to keep trying but i have little faith in my abilities when it comes to this problem of multiple checkboxes. Where, might I ask, do I put the last line? model.Roles roles.Select(R=> new RoleVM{ID=r.ID, Name=r.Name}); – JustJohn Jan 15 '16 at 17:12

0 Answers0