3

I'm building an ASP.NET MVC application and want to use a partial view to display my product-categories. It is going to be a webshop and on each page, below the menubar, I want to show another bar which contains all product-categories.

I want to use a partial view for this. Currently in ~/Views/Categories I created the partial view _CategoriesHeader.cshtml. (I did that by selecting "Partial View" on the "Create New View" dialog, so it's actually a partial view)

The contents of _CategoriesHeader.cshtml are the following:

@model IEnumerable<Webshop.Models.Category>

@{
    Layout = null;
}

<ul>
    @foreach (var category in Model)
    {
        <li>@Html.ActionLink(category.Name, "Category", "Categories", new { ID = category.CategoryID }, null)</li>

    }
</ul>

Now in ~/Views/Shared/_Layout.cshtml I added the following piece of code:

@Html.Partial("~/Views/Categories/_CategoriesHeader.cshtml", new Webshop.DAL.ShopContext().Categories.ToList())

I am wondering if this is the right way to use partial views that require a model. Now it just inline creates a new DbContext object to get all the categories, but I think it's better to have a model. But I don't know how to do this. I did something where the CategoriesController.cs had a method for this partial view, but that didn't work because the containing view already had its own model loaded.

3
  • 3
    Newing up a DbContext in the view goes against the MVC pattern. You should change the model of the main View to be an object that contains all items for the view and any partials. Commented Mar 19, 2015 at 15:23
  • Is there any specific reason why you want to list the product categories as a partial view? Commented Mar 19, 2015 at 15:46
  • Because I want it to be on every page this webapp has. Is there a better way? Commented Mar 19, 2015 at 17:52

4 Answers 4

4

No. You should not do any DAL actions inside a view. I actually would recommend to only use if, foreach and similar statements. Nothing else. Prepare your data in your controller and pass it in.

You should put new Webshop.DAL.ShopContext().Categories.ToList() into your model that is used in the main view, and pass that to the partial view.

@Html.Partial("~/Views/Categories/_CategoriesHeader.cshtml", Model.Categories)

You might need a foreach if you want to render the data in a list.

If you want to do this for every page, you should create a new action, and let that action render, instead of a partial view. (That action should call the partial view). That action can acquire the required information and pass that onto the view.

@Html.Action("CategoriesHeader")
Sign up to request clarification or add additional context in comments.

7 Comments

I think his issue is that the partial is in the layout page. To use your technique he would have to have the categories on every Model for every page (possibly inherit from a base class). Unless I am reading this wrong.
Yeah. The point is that I want to display this list of categories on EVERY page, that's why I put it in _Layout.cshtml. And all those pages already have their own model... So I have no idea how I should do that.
Just derive from a base class and set it there.
How do you mean that?
As far as I can remember you can render the partial from an action for this.
|
2

What you can do is to use Html.Action or Html.RenderAction. This avoid call any DAL from View. You controller most have the action annotated as ChildActionOnly, and inside the action, like above answer comment, use return PartialView.

3 Comments

I tried using this method. In _Layout.cshtml I have @Html.Action("CategoriesHeader", "CategoriesController"). In CategoriesController.cs I have the method CategoriesHeader (annotated with ChildActionOnly) which returns a PartialView (with the _CategoriesHeader.cshtml and the model). But now I get The controller for path '/' was not found or does not implement IController.. I have no idea why and tried some solutions that did not work.
Hmm. I was using "CategoriesController" as controllerName for @Html.Action(), which should be "Categories" (since the compiler knows that it's a controller). This is the solution to the above error.
Just out of curiousity, I was messing around with the PartialViews again (building a shopping cart that should be reloaded when a product is added, which didn't work with ChildActionOnly). But now I removed ChildActionOnly and the site still works. Is ChildActionOnly just to prevent from loading it as a complete page or is there anything else it does?
2

Use child actions.

ShopController.cs

[ChildActionOnly]
public ActionResult CategoryList()
{
    var categories = new Webshop.DAL.ShopContext().Categories.ToList();
    return PartialView("_CategoryList", categories);
}

_CategoryList.cshtml

@model IEnumerable<Webshop.Models.Category>

<ul>
    @foreach (var category in Model)
    {
        <li>@Html.ActionLink(category.Name, "Category", "Categories", new { ID = category.CategoryID }, null)</li>

    }
</ul>

_Layout.cshtml

@Html.Action("CategoryList", "Shop")

1 Comment

This is practically what I've done now, but since it's the same solution as @LeonardoNeninger gave me, I've commented the new error message there.
0

Another approach is to return the partial view from your controller. Your controller action will be responsible for loading the model into the partial view. Your controller code will look something like this:

public PartialViewResult GetYourPartialView(string id)
        {
            var vm = new yourviewmodel();          
            return PartialView("_YourPartialView", vm);
        }

Now, you've got a loaded-up partial view.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.