I'm working on an ASP.NET Core 2.2 MVC app and am trying to implement Bootstrap Dual Listbox plugin for role selection. I have _UserEditorPartial.cshtml
view that can be used to assign roles to a user (the listbox on the right would contain roles assigned):
(The partial has more editable fields, but I think those are irrelevant)
Now, the partial contains data associated with the user I had selected on the parent page. When I select the user, I just pass UserID to ViewUserEditorPartial
and query the database to retrieve the whole list of roles available, marking the IsAssigned
property to true if the user belongs to the role. So now, I have a list of roles and I know which role belongs to the user.
What I'm struggling with is figuring out how to make sure that the roles belonging to the user end up in in the listbox on the right. If the user belongs to Role2
and Role4
, I want my view to be generated like this:
I've found this solution but it's not obvious to me how the two listboxes are correctly populated. I'm thinking after loading the partial I could probably do something with JavaScript, where I separately retrieve the List<RoleUserAssignment>
with AJAX and, depending on the value of IsAssigned
property for each role, generate the <option>
tag in the correct listbox. But I'm wondering is there a better approach?
Also, I'll implement the ability to create users and assign them roles using this solution that I found.
Models:
public class Role
{
public int RoleID { get; set; }
public string RoleName { get; set; }
}
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
}
public class RoleUserAssignment
{
public RoleUserAssignment()
{
Role = new Role();
User = new User();
}
public Role Role { get; set; }
public User User { get; set; }
public bool IsAssigned { get; set; } //true if user has role
}
public class UserEditing
{
public UserEditing()
{
RoleUserAssignments = new List<RoleUserAssignment>();
}
public List<RoleUserAssignment> RoleUserAssignments { get; set; }
}
HTML
@model UserEditing
<script>
$(document).ready(function () {
$('#rolesSelection').bootstrapDualListbox({});
});
</script>
<form id="userEditorForm">
<div>Roles</div>
<select id="rolesSelection" class="form-control" class="form-control" asp-for="@Model.RoleUserAssignments" asp-items="@(new SelectList(Model.RoleUserAssignments, "Role.RoleID", "Role.RoleName"))"
multiple="multiple">
</select>
</form>
ViewUserEditorPartial action:
[HttpGet]
public IActionResult ViewUserEditorPartial(int UserID)
{
UserEditing userEditing = new UserEditing();
userEditing.RoleUserAssignments = _userAdmin.GetRoleUserAssignmentsByUserID(_appSettings.MOPConfigConnectionString, UserID);
return PartialView("_UserEditorPartial", userEditing);
}
What I'm struggling with is figuring out how to make sure that the roles belonging to the user end up in in the listbox on the right.
To achieve this function, you can avoid implementing it in js, it will be easier to implement it in the controller.
You can first get the RoleID
data lists that the user belongs to the role, then put the lists into the ViewData
in the ViewUserEditorPartial
action, and then bind the value of ViewData
to the asp-for
attribute when binding the select.
Here is my demo:
[HttpGet]
public IActionResult ViewUserEditorPartial(int UserID)
{
UserEditing userEditing = new UserEditing();
var roleUserAssignData = _userAdmin.GetRoleUserAssignmentsByUserID(_appSettings.MOPConfigConnectionString, UserID);
userEditing.RoleUserAssignments = roleUserAssignData;
// get the data which IsAssigned field are true and select the RoleID of each data.
ViewData["SelectedRoles"] = roleUserAssignData.Where(x => x.IsAssigned).Select(x => x.Role.RoleID).ToList();
return PartialView("_UserEditorPartial", userEditing);
}
_UserEditorPartial view:
@model UserEditing
<script>
$(document).ready(function () {
$('#rolesSelection').bootstrapDualListbox({});
});
</script>
<form id="userEditorForm">
<div>Roles</div>
<select id="rolesSelection" class="form-control" class="form-control"
asp-for="@ViewData["SelectedRoles"]"
asp-items="@(new SelectList(Model.RoleUserAssignments, "Role.RoleID", "Role.RoleName"))"
multiple="multiple">
</select>
</form>
If allowed, add List<int>
type field named SelectedRoles
in UserEditing
model to store the selected roles is better.
public class UserEditing
{
public UserEditing()
{
RoleUserAssignments = new List<RoleUserAssignment>();
}
public List<int> SelectedRoles { get; set; }
public List<RoleUserAssignment> RoleUserAssignments { get; set; }
}
In ViewUserEditorPartial action, change ViewData sentence to the following:
userEditing.SelectedRoles = roleUserAssignData.Where(x => x.IsAssigned).Select(x => x.Role.RoleID).ToList();
_UserEditorPartial view:
<form id="userEditorForm">
<div>Roles</div>
<select id="rolesSelection" class="form-control" asp-for="@Model.SelectedRoles"
asp-items="@(new SelectList(Model.RoleUserAssignments, "Role.RoleID", "Role.RoleName"))"
multiple="multiple">
</select>
</form>