Introduction: Partial Views

blocks on the floor

As we saw in earlier posts, Hexo supports the idea of partial views. For a reminder here is an example of a partial view:

<head>
    <meta charset="utf-8"/>
    <title><%= config.title %></title>
</head>

Then we can reference the above partial view by adding <%- partial('_partials/global/head') %> to our page.

This seems like extra effort to just add the head to the layout page, isn't it? Why do we want to use this feature of Hexo?

Well for starters, Hexo was not the first to implement partial views. Every web presentation technology I can think of has some concept of partial views. They may not be directly labeled as a partial view, however, they contain tools to assist in solving a similar problem that partial views solve.

So what problems do partial views solve? To answer this, I want to use an example. Say I have a blog and each post has a title property on it. By default when the title is rendered in the view it appears in a h1 tag and it has a style class of title. Maybe it looks something like this: <h1 class="title"><%= post.title %></h1>. If this blog is just a list of posts, we are set. There is a single instance of that title line, we iterate over all the posts and life is merry.

Now, we want to not only display the posts as a list, but we also want to display the post on a single page. All by itself. To do this we will have to create that new page, it will potentially look very similar to the post list, but the page will only contain one post. On this single post page markup, we have to add the same line as before: <h1 class="title"><%= post.title %></h1>. This is not the worst thing in the world, duplicate code in 2 places. We have all seen much more duplicate code in our lives.

Time goes on and we want to add other pages to the site that are not the same layout as a post, but they also have a title. For consistency across the site, the titles should appear the same, right? Okay, we build out this new page markup. Along the top of the markup we have: <h1 class="title"><%= page.title %></h1>. Oddly familiar... Now I am not liking this one bit. We have 3 instances of a title in markup, that if we ever want to change how the title appears, something like we want to change from h1 to h2. We have to find this title in 3 locations and update each. There has to be a better way to do this.

Partial views are the way. Heres' how. First, we create our new partial view:

<h1 class="title"><%= title %></h1>

But, where does title come from in the partial view? We can pass it in from the caller of the partial view.

<%- partial('/_partials/title', { title: post.title })%>
<%- partial('/_partials/title', { title: page.title })%>

Following this partial view pattern, anywhere we want to add a title we use the partial view. All titles will appear the same across the site. As the title changes through time, there is only one location to make the change.

What did we just get with this?

  1. Single responsible component
  2. Less maintenance
  3. Testability
  4. Dependency inversion
  5. Cleaner parent views

Now let's make this scenario a little more realistic. There are certain pages where not only do we want a title, but we also want to make the text italic and we want a subtitle. The first step I would take here is to create a page that uses both these features:

<%- partial('/_partials/title', { title: page.title, italic: true, subtitle: 'some text for testing' })%>

Then, move on to updating the partial view:

<% if (italic) { %>
    <h1 class="title italic"><%= title %></h1>
<% } else { %>
    <h1 class="title"><%= title %></h1>
<% } %>

<% if (subtitle) { %>
    <h3 class="sub-title"><%= subtitle %></h3>
<% } %>

Now if we had unit tests around this, we could quickly update our unit test. Perhaps, we should have started by updating our unit test. Or given this is a personal blog, maybe we just functionally test the scenarios and check it in.

Partial views are pretty powerful. It is an application of the same object-oriented programming patterns we follow, but this time applied to the presentation layer.