Reputation: 2343
I am working with a View
that returns List<ViewModel>
to the Controller
's Create
action method.
Questions:
List<ViewModel>
to the controller? The reason I am doing is that I have to make multiple rows entry to the DB for each user. 2. My Controller
implemenation is incorrect because I am trying to add data through single User object where I have recieved List of ViewModels which is only the representation of the View for single user. So how the controller should be implemented? public ActionResult Create()
method in the controller?Limitations:
PK
Logic:
User would be able to select multiple checkboxes(represents ROLE) for each user and that should be persisted in the database as single row. For example
DB: dbo.User table should have the following entries on Save
(abcdefg, levelA, locationB, Role2, null, null, Y)
(msjdhcdu, levelA, locationB, Role2, null, null, Y) Same user Different Role
(msjdhcdu, levelA, locationB, Role3, null, null, Y) Same user Different Role
USer would be kept on the same page (save VIEW) after the Save button click and showing the recent changes in the database.
ViewModel:
public class UserViewModel
{
public string UserName { get; set; }
public string Level { get; set; }
public string Location { get; set; }
public List<RoleViewModel> Roles { get; set; }
}
public class RoleViewModel
{
public string RoleName{ get; set; }
public bool IsSelected { get; set; }
}
View: I might be doing something very wrong in the VIEW
@model List<Project.ViewModels.UserViewModel>
@using (@Html.BeginForm("Create", "User", FormMethod.Post ,new { id = "UserPermissionForm" }))
{
<table class="table">
<tr>
<th>User</th>
@for (int i = 0; i < Model[0].Roles.Count; i++)
{
<th>
@Model[0].Roles[i].RoleName
</th>
}
</tr>
@for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
@Html.HiddenFor(m => m[i].UserName)
@Model[i].UserName
</td>
@for (int j = 0; j < Model[i].Roles.Count; j++)
{
<td>
@Html.CheckBoxFor(m => m[i].Roles[j].IsSelected)
</td>
}
</tr>
}
</table>
<div class="form-actions">
<button type="submit" class="btn btn-success submit" value="Save">Save changes</button>
</div>
<script>
$('#Submit').click(function () {
let url = '@Url.Action("Create", "Users")'
$.post(url, $("#UserPermissionForm"))
});
</script>
Controller:
[HttpPost]
public ActionResult Create(List<UserViewModel> viewModelList)
{
for (int i= 0; i > viewModelList.Count; i++) {
for (int j = 0; j > viewModelList[i].Roles.Count; j++) {
db.UserDetails.Add(new User
{
username = viewModelList[i].UserName,
level = viewModelList[i].Level,
location = viewModelList[i].Location,
role = viewModelList[i].Roles[j].RoleName,
Approval = "",
Request = "",
Active = "Y"
});
}
db.SaveChanges();
return RedirectToAction("Index","Users");
}
return View(viewModelList); // not right
}
Error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Project.ViewModels.UserViewModel]', but this dictionary requires a model item of type 'Project.Models.User'.
Any guidance/help is appreciated.
EDIT1: View has been added EDIT2: Bsuiness logic added
Upvotes: 2
Views: 1233
Reputation: 218818
Here you're sending a model to the view:
return View(viewModelList);
And that model is of type List<UserViewModel>
. According to the error, however, the view is expecting a model of type User
. Something like this declaration on the view itself:
@model Project.Models.User
So you have two options:
List<UserViewModel>
, making any changes as necessary within the view itself to use that new model type.Project.Models.User
(which would presumably be a transformation of one element from the List<UserViewModel>
?).On a technical level either option is perfectly valid. (Though the two are mutually exclusive, it's one or the other.) It's up to you which option makes more sense for the system you're building, whether or not that view should be operating on an instance or on a list.
Edit: Your edit to the question (to include a view) seems to indicate that you may be looking at the wrong view. The view you're showing us doesn't match the error message you're showing us. Keep in mind that the two exit paths for your controller method (a redirect and a return of a view) probably invoke different views.
In any event, the core of the issue still remains. Somewhere you're providing a view with a type which is different from what it expects. You may have to do some additional debugging to determine where in your code that's happening, but ultimately the problem and potential solution remain the same as described above.
Upvotes: 4