Reputation: 5419
Situation
I have a list of users, which inturn has a list of roles which I want to see editable in a kendo multiselectfor.
Problem
With the code that I have it turns out very weird, at the top it display a bunch of textboxes (for my opinion) and at the place where the multiselect boxes should be all I see are up and down arrows.
My code so far:
foreach (var u in Model.Users)
{
<div class="form-group">
<div class="col-sm-2">
@Html.Label(u.Name)
</div>
<div>
@Html.Kendo().MultiSelectFor(m => u.Roles).BindTo(Model.UserRoles);
</div>
</div>
}
Viewmodel
public class CompanyViewModel
{
public IEnumerable<UserDto> Users { get; set; }
public IEnumerable<UserRoleDto> UserRoles { get; set; }
}
UserDto
public class UserDto
{
public int Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Name
{
get
{
return string.Format("{0} {1} {2}", FirstName, MiddleName, LastName);
}
}
public IEnumerable<SelectListItem> Roles { get; set; }
}
Here's a snippet of what the page looks like when I render it like this
div class="k-widget k-multiselect k-header" unselectable="on" title style>
div class="k-multiselect-wrap k-floatrap" unselectable="on">...</div>
div class="k-widget k-multiselect k-header" unselectable="on" title style>
div class="k-multiselect-wrap k-floatrap" unselectable="on">...</div>
div class="k-widget k-multiselect k-header" unselectable="on" title style>
div class="k-multiselect-wrap k-floatrap" unselectable="on">...</div>
div class="k-widget k-multiselect k-header" unselectable="on" title style>
div class="k-multiselect-wrap k-floatrap" unselectable="on">...</div>
and this keeps repeating itself some more times.
I suspect there is an issue with how I make the multiselectfor based on the user instead of something from the model but my knowlage of kendo is to low to understand how it should be done.
Any help would be much appreciated
Upvotes: 1
Views: 1397
Reputation:
You have multiple issues with your code.
Firstly, Kendo MultiSelectFor()
creates a html <select multiple>
tag (although it hides it using display: none;
and adds its own html, but its the <select>
that is used for binding and posting back to the controller). A <select multiple>
can only bind to, and can only post back an array of simple values types, not complex objects so you cannot bind to a property which is typeof IEnumerable<IEnumerable<SelectListItem>
. Your Roles
property needs to be IEnumerable<int> Roles { get; set; }
assuming your wanting to post back the selected role ID's.
Next your UserRoles
needs to be IEnumerable<SelectListItem>
or SelectList
which is necessary for the .BindTo()
method of the helper.
Finally you cannot use a foreach
loop to bind to collection properties. It will generate duplicate name
attributes that have no relationship to your model and therefor will not bind (and also duplicate id
attributes which is invalid html). You need to use a custom EditorTemplate
for the type in your collection (generally a for
loop would be suitable, but due to an issue with using the helper in a loop, it wont work in your case)
Your view models needs to be
public class CompanyViewModel
{
public IEnumerable<UserViewModel> Users { get; set; }
public IEnumerable<SelectListItem> RoleList { get; set; }
}
public class UserViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
....
[Display(Name = "Roles")]
public IEnumerable<int> SelectedRoles { get; set; }
}
Then create a partial view /Views/Shared/EditorTemplates/UserViewModel.cshtml
@model yourAssembly.UserViewModel
@Html.HiddenFor(m => m.Id)
....
@Html.LabelFor(m => m.SelectedRoles)
@Html.Kendo().MultiSelectFor(m => u.SelectedRoles)
.BindTo((IEnumerable<SelectListItem>)ViewData["roleList"])
....
and in the main view
@model yourAssembly.CompanyViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(m => m.Users, new { roleList = Model.RoleList })
<input type="submit" .../>
}
What is happening here is that EditorFor()
method will generate the html for each UserViewModel
in the collection based on the html in the template. In addition, it passes the SelectList
to the template as additional ViewData
Side note: I recommend you start by using the standard MVC listbox helper
@Html.ListBoxFor(m => u.SelectedRoles, (IEnumerable<SelectListItem>)ViewData["roleList"])
in the template to be sure its all working, and then change to @Html.Kendo().MultiSelectFor()
Upvotes: 2