Life is full of weird coincidences, like when you’re thinking about an old high-school friend and you randomly bump into him the next day.

Well, the programming equivalent of the high-school friend bump happened to me this week: just as I was done implementing a feature for the latest version of Telescope, the Meteor folks released a much easier way to do the same exact thing!

Static VS Dynamic

I’m talking about dynamic template includes. A static template include is the kind we use all the time, like:

{{> foo}}

Where foo is the name of our template.

But a dynamic template include would be something like this:

var myTemplate = "foo"
{{> myTemplate}}

Of course this won’t actually work, because Meteor will simply look for a template named “myTemplate” instead of trying to evaluate the myTemplate variable.

A New Syntax

This is where Meteor 0.8.2 comes in. You can now write this:

{{> UI.dynamic template=myTemplate}}

Optionally, you can also pass a data context to the template:

{{> UI.dynamic template=myTemplate data=myDataContext}}

A Practical Example

So far so good. But what can you do with this new syntax exactly?

Let’s go back to my example from Telescope. Here’s what Telescope’s top navigation menu looks like:

The Telescope top navigation menu.

Looks pretty standard. We have two dropdown menus, a search field, and then another dropdown. It would be easy enough to add another menu item. Just edit the template, add in some HTML, and you’re done.

But to make Telescope easier to customize, I wanted to make it possible to add menu items from outside the template (for example, from within a package).

This meant the menu had to be generated on the fly, and this is where UI.dynamic comes in.

Three Components

I put my menu together with three components. The first one was simply a set of individual templates for each menu item. For example, here’s what the “view” menu’s template looks like:

<template name="viewsMenu">
  {{#if canView}}
    <div class="dropdown">
      <a class="View" href="/">{{i18n "View"}}</a>
      <div class="dropdown-menu">
        <ul role="menu" aria-labelledby="dLabel">
          {{#each views}}
            {{> menuItem this}}
          {{/each}}
        </ul>
      </div>
    </div>
  {{/if}}
</template>

Similarly, I created adminMenu, categoriesMenu, and search templates.

I then created a navItems array containing the list of all templates to display:

navItems = ['viewsMenu', 'adminMenu', 'categoriesMenu'];

That made it easy to add a menu item at any point in the app:

navItems.push('search');

Finally, the cool part: actually displaying the menu.

<ul class="nav site-nav desktop">
  {{#each navItems}}
    <li>
      {{> UI.dynamic template=this}}
    </li>
  {{/each}}
</ul>

The Old Way

If you’re curious, here’s how I was previously doing the same thing, based on this Stack Overflow answer.

To begin with, I was mapping the navItems array to an array of objects of the form {template: Template[templateName]}, and outputting the result as a helper:

Template.nav.helpers({
  navMenus: function () {
    var navMenus = _.map(navItems, function(templateName){
      return {template: Template[templateName]}
    });
    return navMenus;
  }
});

I then included the helper as if it were a template:

<ul class="nav site-nav desktop">
  {{#each navItems}}
    <li>
      {{> template}}
    </li>
  {{/each}}
</ul>

The interesting thing here is that Meteor is somehow smart enough to know that in this case, I’m not trying to include a template named “template”, but actually retrieve data from a helper.

This worked well enough, but I find the new way far less confusing!

Data Contexts

As I said, you can also pass dynamic data contexts with your dynamic template include:

{{> UI.dynamic template=myTemplate data=myDataContext}}

I haven’t yet found a good reason to use this. At first glance, it seems like if both your template and data context could change dynamically it would be hard to guarantee that they always match up.

But I’m sure there must be good use cases for this feature, and I’ll let you know as soon as I find one!

Conclusion

Dynamic template includes are a great way to make your app more flexible and promote code reuse. If you’ve used them in your own apps, don’t hesitate to share your examples in the comments!