I have a layout page which has a partial view. The partial view needs to loop through a property on the view model to show a list of categories. When a category is displayed I need to show a list of documents in that category. /Home/Index
works, but when I try to view /Documents/Category/{id}
, I get an error:
Additional information: The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ViewModels.DocumentViewModel]', but this dictionary requires a model item of type 'ViewModels.HomeViewModel'.
_Layout.cshtml
...
<body>
@Html.Partial("_CategoryViewModel")
<div class="content">
@RenderBody()
</div>
HomeViewModel.cs
public class HomeViewModel {
...
public ICollection<DocumentCategory> Categories { get; set; }
public ICollection<Documents> Documents { get; set; }
...
}
_CategoryViewModel.cshtml (this should show a list of all categories)
@model ViewModels.HomeViewModel
...
@foreach (DocumentCategory item in Model.Categories)
{
<li>
<a href="@Url.Action("Category", "Documents", new { @id = @item.CategoryId })" title="View documents in the @item.Name category">
<span class="fa fa-files-o"></span> @item.Name
</a>
</li>
}
DocumentsController.cs
public ActionResult Category(int id)
{
var thisCategory = _ctx.Categories.Get(c => c.CategoryId == id).FirstOrDefault();
IEnumerable<DocumentViewModel> docs = null;
if(thisCategory == null)
{
TempData.Add("errorMessage", "Invalid category");
} else {
docs = thisCategory.Documents.ToList();
}
return View("Category", docs);
}
What's happening kind of makes sense - the PartialView
on the Layout page needs to enumerate over a collection which isn't present in the ViewModel
I'm using. I have no idea how to achieve this - the only way would seem to be to add a Categories property to every ViewModel
in my site.
By default, using @Html.Partial()
will pass the current model to the partial view, and because your Category.cshtml
view uses @model List<DocumentViewModel>
, then List<DocumentViewModel>
is passed to a partial that expects HomeViewModel
.
If you want to render a partial view for HomeViewModel
on every page, then use @Html.Action()
to call a ChildActionOnly
method that returns the partial
[ChildActionOnly]
public ActionResult Categories
{
var model = new HomeViewModel()
{
.... // initialize properties
}
return PartialView("_CategoryViewModel", model)
}
and in the layout
@Html.Action("Categories", yourControllerName)
// or
@{ Html.RenderAction("Categories", yourControllerName); }