Templates

To ease into Meteor development, we'll adopt an outside-in approach. In other words we'll build a "dumb" HTML/JavaScript outer shell first, and then hook it up to our app's inner workings later on.

This means that in this chapter we'll only concern ourselves with what's happening inside the /client directory.

If you haven't done so already, create a new file named main.html inside our /client directory, and fill it with the following code:

<head>
  <title>Microscope</title>
</head>
<body>
  <div class="container">
    <header class="navbar navbar-default" role="navigation"> 
      <div class="navbar-header">
        <a class="navbar-brand" href="/">Microscope</a>
      </div>
    </header>
    <div id="main">
      {{> postsList}}
    </div>
  </div>
</body>

<%= caption "client/main.html" %>

This will be our main app template. As you can see it's all HTML except for a single {{> postsList}} template inclusion tag, which is an insertion point for the upcoming postsList template. For now, let's create a couple more templates.

Meteor Templates

At its core, a social news site is composed of posts organized in lists, and that's exactly how we'll organize our templates.

Let's create a /templates directory inside /client. This will be where we put all our templates, and to keep things tidy we'll also create /posts inside /templates just for our post-related templates.

<% note do %>

Finding Files

Meteor is great at finding files. No matter where you put your code in the /client directory, Meteor will find it and compile it properly. This means you never need to manually write include paths for JavaScript or CSS files.

It also means you could very well put all your files in the same directory, or even all your code in the same file. But since Meteor will compile everything to a single minified file anyway, we'd rather keep things well-organized and use a cleaner file structure.

<% end %>

We're finally ready to create our second template. Inside client/templates/posts, create posts_list.html:

<template name="postsList">
  <div class="posts">
    {{#each posts}}
      {{> postItem}}
    {{/each}}
  </div>
</template>

<%= caption "client/templates/posts/posts_list.html" %>

And post_item.html:

<template name="postItem">
  <div class="post">
    <div class="post-content">
      <h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
    </div>
  </div>
</template>

<%= caption "client/templates/posts/post_item.html" %>

Note the name="postsList" attribute of the template element. This is the name that will be used by Meteor to keep track of what template goes where (note that the name of the actual file is not relevant).

It's time to introduce Meteor's templating system, Spacebars. Spacebars is simply HTML, with the addition of three things: inclusions (also sometimes known as “partials”), expressions and block helpers.

Inclusions use the {{> templateName}} syntax, and simply tell Meteor to replace the inclusion with the template of the same name (in our case postItem).

Expressions such as {{title}} either call a property of the current object, or the return value of a template helper as defined in the current template's manager (more on this later).

Finally, block helpers are special tags that control the flow of the template, such as {{#each}}…{{/each}} or {{#if}}…{{/if}}.

<% note do %>

Going Further

You can refer to the Spacebars documentation if you'd like to learn more about Spacebars.

<% end %>

Armed with this knowledge, we can start to understand what's going on here.

First, in the postsList template, we're iterating over a posts object with the {{#each}}…{{/each}} block helper. Then, for each iteration we're including the postItem template.

Where is this posts object coming from? Good question. It's actually a template helper, and you can think of it as a placeholder for a dynamic value.

The postItem template itself is fairly straightforward. It only uses three expressions: {{url}} and {{title}} both return the document's properties, and {{domain}} calls a template helper.

Template Helpers

Up to now we've been dealing with Spacebars, which is little more than HTML with a few tags sprinkled in. Unlike other languages like PHP (or even regular HTML pages, which can include JavaScript), Meteor keeps templates and their logic separated, and these templates don't do much by themselves.

In order to come to life, a template needs helpers. You can think of these helpers as the cooks that take raw ingredients (your data) and prepare them, before handing out the finished dish (the templates) to the waiter, who then presents it to you.

In other words, while the template's role is limited to displaying or looping over variables, the helpers are the one who actually do the heavy lifting by assigning a value to each variable.

<% note do %>

Controllers?

It might be tempting to think of the file containing all of a template's helpers as a controller of sorts. But that can be ambiguous, as controllers (at least in the MVC sense) usually have a slightly different role.

So we decided to stay away from that terminology, and simply refer to “the template's helpers“ or “the template's logic” when talking about a template's companion JavaScript code.

<% end %>

To keep things simple, we'll adopt the convention of naming the file containing the helpers after the template, but with a .js extension. So let's create posts_list.js inside client/templates/posts right away and start building our first helper:

var postsData = [
  {
    title: 'Introducing Telescope',
    url: 'http://sachagreif.com/introducing-telescope/'
  }, 
  {
    title: 'Meteor',
    url: 'http://meteor.com'
  }, 
  {
    title: 'The Meteor Book',
    url: 'http://themeteorbook.com'
  }
];
Template.postsList.helpers({
  posts: postsData
});

<%= caption "client/templates/posts/posts_list.js" %>

If you've done it right, you should now be seeing something similar to this in your browser:

<%= screenshot "3-1", "Our first templates with static data" %>

We're doing two things here. First we're setting up some dummy prototype data in the postsData array. That data would normally come from the database, but since we haven't seen how to do that yet (wait for the next chapter!) we're “cheating” by using static data.

Second, we're using Meteor's Template.postsList.helpers() function to create a template helper called posts that returns the postsData array we just defined above.

If you remember, we are using that posts helper in our postsList template:

<template name="postsList">
  <div class="posts page">
    {{#each posts}}
      {{> postItem}}
    {{/each}}
  </div>
</template>

<%= caption "client/templates/posts/posts_list.html" %>

Defining the posts helper means it is now available for our template to use, so our template will be able to iterate over our postsData array and pass each object contained within to the postItem template.

<%= commit "3-1", "Added basic posts list template and static data." %>

The domain Helper

Similarly, we'll now create post_item.js to hold the postItem template's logic:

Template.postItem.helpers({
  domain: function() {
    var a = document.createElement('a');
    a.href = this.url;
    return a.hostname;
  }
});

<%= caption "client/templates/posts/post_item.js" %>

This time our domain helper's value is not an array, but an anonymous function. This pattern is much more common (and more useful) compared to our previous simplified dummy data example.

<%= screenshot "3-2", "Displaying domains for each links." %>

The domain helper takes a URL and returns its domain via a bit of JavaScript magic. But where does it take that url from in the first place?

To answer that question we need to go back to our posts_list.html template. The {{#each}} block helper not only iterates over our array, it also sets the value of this inside the block to the iterated object.

This means that between both {{#each}} tags, each post is assigned to this successively, and that extends all the way inside the included template's manager (post_item.js).

We now understand why this.url returns the current post's URL. And moreover, if we use {{title}} and {{url}} inside our post_item.html template, Meteor knows that we mean this.title and this.url and returns the correct values.

<%= commit "3-2", "Setup a domain helper on the postItem." %>

<% note do %>

JavaScript Magic

Although this is not specific to Meteor, here's a quick explanation of the above bit of “JavaScript magic”. First, we're creating an empty anchor (a) HTML element and storing it in memory.

We then set its href attribute to be equal to the current post's URL (as we've just seen, in a helper this is the object currently being acted upon).

Finally, we take advantage of that a element's special hostname property to get back the link's domain name without the rest of the URL.

<% end %>

If you've followed along correctly, you should be seeing a list of posts in your browser. That list is just static data, so it doesn't take advantage of Meteor's real-time features just yet. We'll show you how to change that in the next chapter!

<% note do %>

Hot Code Reload

You might have noticed that you didn't even need to manually reload your browser window whenever you changed a file.

This is because Meteor tracks all the files within your project directory, and automatically refreshes your browser for you whenever it detects a modification to one of them.

Meteor's hot code reload is pretty smart, even preserving the state of your app in-between two refreshes!

<% end %>

Last updated