0

I've created a PartialView and here's how I'm calling it.

<div id="bodyarea">
    <div id="leftnavigationbar">     
        @Html.Partial("_SideBarMenu")
    </div>

    <div id="mainbody">
        @RenderBody()
    </div>

    <div id="footer">
    </div>
</div>

Here's the actual code for the PartialView:

@model Cumavi.ViewModels.SidebarNavigation

<ul>
    @foreach (var category in Model.Categories)
    {
        <li>category.Name</li>
    }
</ul>

As you can see, I'm using a custom created ViewModel called SidebarNavigation, which has this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Cumavi.Models;

namespace Cumavi.ViewModels
{
    public class SidebarNavigation
    {
        public IEnumerable<Category> Categories { get; private set; }

        public SidebarNavigation()
        {
            CategoryRepository categoryRepo = new CategoryRepository();
            this.Categories = categoryRepo.FindAllCategories();
        }
    }
}

The problem is that when I run the application, I get a null reference exception on the foreach loop.

I don't understand the reason though. In the ViewModel, SidebarNavigation, in the constructor I'm actually filling the variable. Any suggestions?

Edit:

Another thing I've noticed is that the constructor for my ViewModel class is never actually called. :S That must be why the Categories attribute is null. Suggestions?

Edit 2:

Another problem! I'm using _Layout.cshtml file to create the common look (masterpage) for the application. Since no controller is associated to this file, how can I pass a model to it? :S

2
  • and you're sure the Exceptions is on the line @foreach (var category in Model.Categories) and not on <li>category.Name</li> ? Commented Dec 13, 2010 at 0:43
  • @Pauli: Yep, 110% sure that it's on the foreach line. Thanks for the help, really appreciate your time. Commented Dec 13, 2010 at 0:46

3 Answers 3

3

You're not passing the model through to the partial view.

@Html.Partial("_SideBarMenu")

All that does is render a partial view called _SideBarMenu.cshtml

But your partial view expects: Cumavi.ViewModels.SidebarNavigation

Pass through the model:

@Html.Partial("_SideBarMenu", model)

Also - why do you have a ctor for SidebarNavigation where you populate the categories?

Your controller should instantiate that viewmodel:

var model = new SideBarNavigational { Categories = repository.GetSomething() };
return View (model);

You should never make calls to your repository via your view models.

Sign up to request clarification or add additional context in comments.

7 Comments

That makes complete sense, but now I'm back to square one. :P Where do I get that model from? I imagine from the Controller but the entire point of using a PartialView was to be able to call this from everywhere without repeating the model loading on every controller. Suggestions? Thanks!
Regarding your edit: Where would I write that code? I don't want to repeat that category fetching in every single controller. That seems to be the only way though. :\
Partial Views are use to re-use HTML, not re-use the model. Your partial view should accept a model (which it does). That model comes from the view which contains the partial. And that view gets the model from the controller. It should always flow that way. Controller -> Gets Model -> Passes to View -> View Renders Partial and Passes Model -> Partial Renders HTML with Model.
Create a base controller class that all other controllers inherit from. That will allow you to keep all the navigation logic in one place.
@Serg. You can also create an ActionFilter that updates the ViewModel, adding to it as necessary. That ActionFilter can apply to all Controllers/Actions or some subset of them.
|
0

remove your private accessor

public IEnumerable<Category> Categories { get; set; }

Are you sure that categoryRepo.FindAllCategories(); returns not null?

1 Comment

It's strange, the constructor is never actually called, according to my breakpoint. I don't know why. To clarify, that line of FindAllCategories is never called.
0

For your scenario (if I understand it correctly) you should use Html.Action instead of Html.Partial and create a new action decorated with ChildActionOnlyAttribute. As mentioned in a comment to a different answer, partials are meant for reusable markup. For reusable data+markup you can use child actions.

For example you can create a SharedController class:

public class SharedController : Controller
    [ChildActionOnly]
    public ViewResult SideBar() {
        return new PartialView(new SideBarModel());
    }
}

And then have a SideBar.cshtml view:

@model SideBarModel
.... Render contents here

And then from your _Layout.cshtml file you call:

@Html.Action("SideBar", "Shared")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.