How To Use MVC Partials In Umbraco

One of the main benefits of using MVC views is the ability to split functionality up in order to provide greater re-use.  In MVC, we can achieve this re-use by making use of partials.  If you come from a web forms background and you are still new to MVC, you can think of a partial in the same way that you would a user control.  In today’s guide, we are going to implement a partial so we can display a very basic header on any page we want to.  In today’s guide we are going to be working with this homepage template:

@inherits UmbracoTemplatePage
@{
Layout = null;
}
@foreach (var page in Model.Content.DescendantOrSelf(1).Children.Where(x => x.IsVisible()))
{
<li>
<a href="@page.Url">
@page.Name
</a>
@if (page.Children.Where(x => x.IsVisible()).Any())
{
<ul>
@foreach (var subMenu in page.Children.Where(x => x.IsVisible()))
{
<li>
<a href="@subMenu.Url">
@subMenu.Name
</a>
</li>
}
</ul>
}
</li>
}

The Partial

As our website will have numerous document types and templates, duplicating the HTML for the menu on every page is a bit crap.  If we ever wanted to change the menu we would have to update it on every template.  Instead, it would be much better to create a partial called ‘Header’ and include a single include to the partial whenever it’s required. NOTE: In production you call the ‘Header’ from the layout rather than the template.

The first thing we need to do is create a new MVC razor view called ‘Header.cshtml’ in ‘~/Views/Partials’ and copy the menu code into it.

@model IPublishedContent
@foreach (var page in Model.Content.DescendantOrSelf(1).Children.Where(x => x.IsVisible()))
{
<li>
<a href="@page.Url">
@page.Name
</a>
@if (page.Children.Where(x => x.IsVisible()).Any())
{
<ul>
@foreach (var subMenu in page.Children.Where(x => x.IsVisible()))
{
<li>
<a href="@subMenu.Url">
@subMenu.Name
</a>
</li>
}
</ul>
}
</li>
}

Notice the import statement at the top inheriting from IPublishedContent rather then UmbracoTemplatePage.  In our main template view we can now call the partial using this snippet:

@Html.Partial("Header", Model)

View Models

There is one issue with this bit of code; the menu will always change depending on where the user is on your website.  If the user is visiting third level pages, they will only see the pages underneath.  Instead, the menu should always display the top level pages or have the ability to display pages from wherever we want.  In order to do this, we will need to split our code up a little and introduce a view model class.  The view model will take in a list of pages in the constructor to display, like so:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core.Models;
namespace SampleSite.Models
{
public class HeaderViewModel
{
private IEnumerable<IPublishedContent> menuItems;
public HeaderViewModel(IEnumerable<IPublishedContent> menuItems)
{
this.menuItems = menuItems;
}
public List<IPublishedContent> MenuItems
{
get
{
return menuItems.ToList();
}
}
}
}

The next step is to update the header partial to work with the view model instead of an IPublishedContent.

@model SampleSite.Models.HeaderViewModel
@foreach (var page in Model.MenuItems)
{
<li>
<a href="@page.Url">
@page.Name
</a>
@if (page.Children.Where(x => x.IsVisible()).Any())
{
<ul>
@foreach (var subMenu in page.Children.Where(x => x.IsVisible()))
{
<li>
<a href="@subMenu.Url">
@subMenu.Name
</a>
</li>
}
</ul>
}
</li>
}

Now we need to pass the View Model from the template into the partial:

@inherits UmbracoTemplatePage
@{
Layout = null;
}
@Html.Partial("Header", 
new SampleSite.Models.HeaderViewModel(Model.Content.DescendantOrSelf(1).Children.Where(x => x.IsVisible())))

In the snippet above, we pass in the list of child pages of the current page via the view models constructor.  The view model exposes these menu items via a custom property called ‘MenuItems’.  In the partial, set the inheriting type as ‘HeaderViewModel’.  In our partial, we can then access that property by calling ‘Model.MenuItems’

Getting The HomePage

The only thing that is still wrong with the code is that the menu will still change depending on where in the website hierarchy it is called.  Instead, we want to change the code so the content passed into the view model is based on the home page and not the current page.

In Umbraco if you want to access your homepage via the API then you can use:

Umbraco.TypedContentAtRoot().First();

To access the homepage, now our updated template code looks like this:

@inherits UmbracoTemplatePage
@{
Layout = null;
}
@Html.Partial("Header", 
new SampleSite.Models.HeaderViewModel(Umbraco.TypedContentAtRoot().First().DescendantOrSelf(1).Children.Where(x => x.IsVisible())))

Conclusion

In today’s guide, we’ve implemented a partial view for our menu so it can be displayed on any page without having to duplicate the HTML.  Instead of only limiting the menu to display pages from the current page, we created a header view model that we pass in a collection of pages (IPublishedCOntent).  We then updated the code for our template to display the pages underneath the homepage, using ‘Umbraco.TypedContentAtRoot().First()’ rather than having the menu changed based on the location in the page hierarchy of the current user.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

1 reply

Trackbacks & Pingbacks

  1. […] free to style your website however you want. In my example, I’m going to continue on from, How To Use MVC Partials In Umbraco and create a layout that includes a reference to the header partial created in that […]

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *