1

I have the following cshtml form

@using (Html.BeginForm(Html.BeginForm("Create", "UserRole", Model, FormMethod.Post)))
{
   @Html.AntiForgeryToken()
   @Html.ValidationSummary(true)

   <fieldset>
       <legend>Role</legend>

       <div class="editor-label">
           @Html.Label(Model.User.UserName)
       </div>
       <div class="editor-field">
           @Html.CheckBoxList(Model.CheckboxList)
       </div>

       <p>
           <input type="submit" value="Create" />
       </p>
   </fieldset>
}

And I wish to get the Model.CheckboxList selected Items in my action.

I have the following Create Action in my Controller

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(UserRoleViewModel userRoleViewModel)
    {
        if (ModelState.IsValid)
        {
            //_context.Role.Add(role);
            //_context.SaveChanges();
            //return RedirectToAction("Index");
        }

        return View(viewModel);
    }

However the viewModel.CheckboxList is 0.

How can I pass the selected values of the checkboxlist, and also the Model.User to the Controller Action?

My ViewModel looks like this :-

    public User User { get; set; }
    public IEnumerable<Role> RoleList { get; set; }

    public List<UserRoleViewModel> UserList { get; set; }

    public IEnumerable<SelectListItem> CheckboxList { get; set; }

    public UserRoleViewModel()
    {
    }

    public UserRoleViewModel(User user, IEnumerable<Role> roleList )
    {
        User = user;
        RoleList = roleList;
    }

Thanks for your help and time!

UPDATE ----------- After reading this post enter link description here, I tried to adapt my code to follow the example, but I am still finding problems with this updated code.

Now I have the following :-

cshtml :-

@model IEnumerable<MvcMembership.ViewModels.RoleCheckboxListViewModel>

    @using (Html.BeginForm())
    {
        @Html.EditorForModel()
        <input type="submit" value="OK" />
    }

Views/Role/EditorTemplates/RoleCheckboxListViewModel.cshtml

@model MvcMembership.ViewModels.RoleCheckboxListViewModel
@Html.HiddenFor(x => x.RoleId)
@Html.HiddenFor(x => x.RoleName)
<div>
   @Html.CheckBoxFor(x => x.Checked)
   @Html.LabelFor(x => x.Checked, Model.RoleName)
</div>

ViewModels :-

public class RoleCheckboxListViewModel
{
    public string RoleId { get; set; }
    public string RoleName { get; set; }
    public bool Checked { get; set; }
}

and the controller action is as follows :-

        public ActionResult Create(int? uid)
    {
        var checkBoxList = new[]
        {
            new RoleCheckboxListViewModel() { 
                    RoleId = "1", Checked = true, RoleName = "item 1"  },
            new RoleCheckboxListViewModel() { 
                    RoleId = "2", Checked = true, RoleName = "item 2" },
            new RoleCheckboxListViewModel() { 
                    RoleId = "3", Checked = true, RoleName = "item 3" },
        };

        return View(checkBoxList);
    }

The problem I have now is that on the Create.cshtml. I cannot see the checkboxlist, but only 123 displayed as well as the OK button.

Any help would be very much appreciated cause I am at a dead end at the moment.

Community
  • 1
  • 1
JMon
  • 3,387
  • 16
  • 63
  • 102
  • possible duplicate of [CheckboxList in MVC3 View and get the checked items passed to the controller](http://stackoverflow.com/questions/5284395/checkboxlist-in-mvc3-view-and-get-the-checked-items-passed-to-the-controller) – Imad Alazani Aug 12 '13 at 07:38
  • already looked at that solution but did not help, still getting trouble persisting the viewModel – JMon Aug 12 '13 at 07:44
  • I can't see `public bool Checked { get; set; }` for your model. Go through the post i suggested thoroughly – Imad Alazani Aug 12 '13 at 07:45
  • ok and how do I set the Checked flag? – JMon Aug 12 '13 at 07:48
  • followed that post, still getting null values though – JMon Aug 12 '13 at 08:19
  • @PKKG I updated the question following the post you suggested but I am still getting problems – JMon Aug 12 '13 at 09:47
  • **[Iterate the model like this now](http://stackoverflow.com/a/6381496/2015869)** – Imad Alazani Aug 12 '13 at 09:50

2 Answers2

7

I've accomplished this with the following parts:

1) A view model for the child element that adds the bool property that will represent whether or not the checkbox is checked in the View later... ie:

public class CategoryViewModel
{
    public int ID { get; set; }
    public string Name { get; set; }
    public bool Assigned { get; set; }
}

2) A view model for the parent element that adds a collection property for this new child element view model, ie:

public class ManufacturerViewModel
    {
        public Manufacturer Manufacturer { get; set; }
        public IList<CategoryViewModel> Categories { get; set; }

        public ManufacturerViewModel()
        {
            Categories = new List<CategoryViewModel>();
        }
    }

3) A service layer method for getting a list of all child elements, while also setting the bool property for each ("Assigned" in my example). To be used by your controller.

public IList<CategoryViewModel> GetCategoryAssignments(Manufacturer mfr)
        {
            var categories = new List<CategoryViewModel>();
            foreach (var category in GetCategories())
            {
                categories.Add(new CategoryViewModel
                {
                    ID = category.ID,
                    Name = category.Name,
                    Assigned = mfr.Categories.Select(c => c.ID).Contains(category.ID)
                });
            }
            return categories;
        }

4) A method for updating the parent item's collection based on your checkboxlist selections. To be used by your controller.

public void UpdateCategories(string[] selectedCategories, ManufacturerViewModel form)
        {
            if (selectedCategories == null)
                selectedCategories = new string[] { };
            var selectedIds = selectedCategories.Select(c => int.Parse(c)).ToList();
            var assignedIds = form.Manufacturer.Categories.Select(c => c.ID).ToList();
            foreach (var category in GetCategories())
            {
                if (selectedIds.Contains(category.ID))
                {
                    if (!assignedIds.Contains(category.ID))
                        form.Manufacturer.Categories.Add(category);
                }
                else
                {
                    if (assignedIds.Contains(category.ID))
                        form.Manufacturer.Categories.Remove(category);
                }
            }
        }

5) Modifications to your Create/Edit view. ie:

@Html.EditorFor(model => model.Categories)

You must also add this so that the original assigned values are included in post data. You'll have to add a HiddenFor for each property that you have set as Required through validation.

for (int i = 0; i < Model.Manufacturer.Categories.Count; i++)
    {
        @Html.HiddenFor(model => model.Manufacturer.Categories[i].ID);
        @Html.HiddenFor(model => model.Manufacturer.Categories[i].Name);
    }

6) And finally, a new EditorTemplate for your child view model element. ie:

@model YourProject.ViewModels.CategoryViewModel
<li>
    <input type="checkbox" 
        id="@string.Format("cb{0}{1}", @Model.Name, @Model.ID)" 
        name="selectedCategories" //Notice this name corresponds to string[] selectedCategories so that it can be extracted from the post data
        value="@Model.ID"
        @(Html.Raw(Model.Assigned ? "checked=\"checked\"" : "")) />
    <label for="@string.Format("cb{0}{1}", @Model.Name, @Model.ID)">@Model.Name</label>
    @Html.HiddenFor(model => model.ID)
</li>

Hopefully my own application gives you a better idea of how to solve this issue.

2

Store your selected value into the variable as follows, and pass it to an hidden field, then you can access it easily

var modelSelected = document.getElementById("modelName");
document.getElementById('selectedModel').value =
   modelSelected.options[modelSelected.selectedIndex].text;

<input id="selectedModel" name="selectedModel" type="hidden" runat="server" />
Pandiyan Cool
  • 6,381
  • 8
  • 51
  • 87