Sitecore MVC Renderings with Layouts and Conditional Sections

In a previous post, I outlined a method to incorporate a common Razor mechanic (layout inheritance) to create similar page layouts while allowing for variations between different Sitecore data templates.  While it isn’t common in some circles, it was at least familiar since it is how standard MVC handle markup reuse.  But the same approach isn’t limited to full page structures; it can also be used on a smaller scale for individual Sitecore renderings.

Some Background

Sitecore MVC renderings can be thought of as miniature or micro pages that are aggregated to form a larger, complete presentation.  Each have their own encapsulated model, view and controller triad and should be considered independent.  When properly executed, you can break-up your page into several manageable parts without having to try to account for every feature and component all at once.  It’s better to have a handful of isolated renderings than trying to make a single rendering do everything.  This isn’t just for the programming effort; it offers more options for customization and personalization in the long run.

The Common Scenario

Most teams break up the design, front-end and back-end development between different members.  The designer may try to find consistency between pages, creating a similar look-and-feel for something like a page header used between a person’s biography page or an article.  The front-end developer might see those similarities and create a single bundle of HTML and CSS to express them.

Unfortunately, common presentation doesn’t always mean common data.  And for good reason: you wouldn’t want to force personal biographies and articles to have identical fields just so make the programming easy.  So we’ll want to find an efficient way to bridge that gap while still supporting requirements like the Experience Editor and personalization.

Start Small

Given the open/close syntax of HTML tags, reusing small blocks of markup for elements is easy but defining set containers with varying contents is more difficult.  This is where Razor layouts come in handy once again.  Let’s break our header component into its pieces using sections.

@model IHeader
<header class="@ViewBag.CssClasses" @(Model.IsJavaScriptEnabled ? "data-animated" : "")>
	<h1>@RenderSection("Title")</h1>
	
	@if (IsSectionDefined("Subtitle")
	{
		<h2>@RenderSection("Subtitle")</h2>
	}
	
	@if (IsSectionDefined("Summary")
	{
		<div class="summary">@RenderSection("Summary")</div>
	}
</header>
@RenderBody()

A couple of things to point out:

  • We’re using an interface (IHeader) as the model for our layout. All views that extend it will need to bind with models that implement that interface. In our example, we have a “IsJavaScriptEnabled” property we’ll set at the model/controller level.
  • For variations we don’t want or need to set at the model/controller, we can use the ViewBag. This should probably be done sparingly, specifically for things that are purely presentation related.
  • We have not incorporated any specific Sitecore fields.  That will come later when we extend this view as a layout.  Instead, we’re describing things generically.
  • Both the “Subtitle” and “Summary” sections are optional.  The outer markup will only display if there is content to show.
  • We have to make a call to “RenderBody()”. I usually reserve this for any kind extra markup that needs to display after the standard markup.

Get Specific

Now we’ll make two views that use the first as a layout and start incorporate their unique data.

@model ProfessionalBiographyModel
@{
	Layout = "~/Areas/Main/Views/Shared/_Header.cshtml";
	ViewBag.CssClasses = "biography";
}

@section Title
{
	@Html.Glass().Ediable(Model.Item, x => x.FirstName)
	@Html.Glass().Ediable(Model.Item, x => x.LastName)
}

@if (Model.ShowJobTitle)
{
	@section Subtitle
	{
		@Html.Glass().Ediable(Model.Item, x => x.Jobtitle)
	}
}

@if (Model.ShowSpecialties)
{
	@section Summary
	{
		@Html.Glass().Ediable(Model.Item, x => x.Specialties)
	}
}
@model ArticleModel
@{
	Layout = "~/Areas/Main/Views/Shared/_Header.cshtml";
}

@section Title
{
	@Html.Glass().Ediable(Model.Item, x => x.Headline)
}

@if (Model.ShowAuthor)
{
	@section Subtitle
	{
		<a href="@Model.Author.Url">@Model.Author.Name</a>
	}
}

@if (Model.ShowAbstract)
{
	@section Summary
	{
		@Html.Glass().Ediable(Model.Item, x => x.Abstract)
	}
}

In both cases, we’re outputting one or more Sitecore fields within a section. We can even reference properties directly on the model that may not come directly from Sitecore (ex. “Model.Author” in the article). I personally prefer wrapping Glass-mapped items with a custom class so I can add properties to control flow.

The tricky part is conditional use of the sections. Using Boolean properties specific to each model, we’re deciding to use sections from the layout only if they are needed.

Conclusion

If you’re already experienced using C# interfaces to find common data and features between your objects, Razor layouts and their sections are a natural progression of those concepts. Done on the small scale with individual renderings, you can get a lot of mileage from a small amount of HTML and a wide array of data from Sitecore.

Leave a Reply