Let's start dividing our markup into templates. Meteor has its own templating system named Spacebars. Spacebars is inspired by Handlebars and we'll be using it to insert dynamic content into our HTML.
Let's start by creating a new views
directory called application
where we'll put our templates that will persist throughout all components of Jabberblocy.
$ mkdir client/views/application
Inside, we'll create a layout.html
file where we'll hold all of our the content from our body
tag.
$ touch client/views/application/layout.html
We'll be using our first Spacebars feature here, called partials. Partials allow us to put HTML blocks (usually in separate files) within other templates. In main.html
, let's take out the content we had in between the body
tags and put it into layout.html
.
<template name="layout">
<aside class="sidebar">
<h5 class="room-label">Participants <i class="ion-person-stalker"></i></h5>
</aside>
<section class="main-container">
<header class="main-header">JabberBlocy</header>
</section>
</template>
Notice that we've wrapped our HTML in a special <template>
tag. The name
attribute of this tag allows us to identify the template in other HTML files. Using this name, we can now replace that markup in main.html
and use the Spacebars syntax for partials.
<head>
<title>JabberBlocy</title>
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.17.2/build/cssreset/cssreset-min.css">
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans:300,400,700">
<link rel="stylesheet" type="text/css" href="http://code.ionicframework.com/ionicons/1.5.2/css/ionicons.min.css">
</head>
<body>
+ {{> layout}}
</body>
Spacebars uses double curly braces to signify that some kind of Spacebars logic will be populated in this part of the template. In this case, the greater than (>
) symbol is Spacebar's way of denoting that we want to insert a partial here. Notice that the name following the >
is identical to our name
attribute on the <template>
tag. This is how Spacebars knows which template to insert.
Now that we know how partials work, we can start creating more templates to be included as partials in our existing templates. The first we'll create is a template named messageList
that will hold the markup for the messages in our chatroom.
Let's create a messages
directory in our views
directory where we'll hold all of our message-related partials. We'll also put our first template file in it, named message_list.html
.
$ mkdir client/views/messages
$ touch client/views/messages/message_list.html
Even though we haven't populated it yet, let's add the reference to the messageList
template in layout.html
.
<template name="layout">
<aside class="sidebar">
<h5 class="room-label">Participants <i class="ion-person-stalker"></i></h5>
</aside>
<section class="main-container">
<header class="main-header">JabberBlocy</header>
+ {{> messageList}}
</section>
</template>
We'll fill the messageList
template with our necessary markup, and include a nice feature of Spacebars called a block helper, along with a reference to another partial within that block.
<template name="messageList">
<div class="message-list">
{{#each messages}}
{{> messageItem}}
{{/each}}
</div>
</template>
The {{#each}}
block helper in this template will allow us to insert a partial named messageItem
for every element in the messages
array. Where does that messages
data come from, and how can we associate it with the message list template? For that, we have Spacebar's template helpers.
Meteor likes to keep its JavaScript logic separate from its templates. Template helper definitions allow us to maintain that separation. The convention in Meteor is to name the JavaScript file similarly to the template that it is managing. Let's create the file that will hold our helper logic and manage our data for us.
$ touch client/views/messages/message_list.js
Inside message_list.js
, we'll create an array of messages that we'll pass to the {{#each}}
block helper from earlier.
messageData = [
{
name: "Joe Lipper",
content: "Wow building a chat app with Meteor is so easy!"
},
{
name: "Mike Jewett",
content: "Yeah wow! What a great framework. I can't wait to keep building this thing out!"
},
{
name: "Joe Lipper",
content: "Hang in there -- we've only scratched the surface on this thing."
}
];
Template.messageList.helpers({
messages: messageData
});
Notice that when we call the
helpers
method on theTemplate
, we use the middle part to identify the precise name of the template we want the helper to work with.
If you've dealt with an MVVM framework like Angular before, you might be thinking that this behavior looks consistent with that of a controller. Template helpers are similar, but generally only act as a place to hold data that the templates can act on. Other logic that might be held in a controller is defined elsewhere in Meteor -- we'll get into that in a bit.
Now that we have data that we can use to populate our individual messages with, we can create our messageItem
partial that we referenced in the {{#each}}
block helper in message_list.html
. We'll call the file that holds the template message_item.html
and put it in our messages
directory with the other message views.
$ touch client/views/messages/message_item.html
And we'll add our markup:
<template name="messageItem">
<div class="message-item">
<h6 class="message-sender">{{name}}</h6>
<p class="message-content">
{{content}}
</p>
</div>
</template>
Notice that the properties of the objects in our messageData
array are accessible in the messageItem
template. This is because the template is included in the scope of the {{#each}}
block, so every individual template is passed the object that corresponds to its instance. Meteor treats the template like a wrapper object for the data, which makes it accessible simply by property name within the template. Therefore there is no need to prepend messageItem
to it.
To bring the look of our templates up-to-date with the app, let's add some styling to style.css
.
/* ... */
.main-container .main-header {
background-color: white;
padding: 24px;
font-family: "Open Sans";
color: rgb(157,158,164);
}
+
+.message-list {
+ position: absolute;
+ top: 70px;
+ width: 100%;
+ overflow-y: scroll;
+ padding-right: 36px;
+ padding-left: 36px;
+ box-sizing: border-box;
+}
+
+.message-item {
+ position: relative;
+ width: 100%;
+ border-bottom: 1px solid rgb(227,229,232);
+}
+
+.message-item .message-sender {
+ font-family: "Open Sans";
+ color: rgb(50,51,54);
+ font-size: 14px;
+ font-weight: 700;
+ margin-top: 16px;
+ margin-bottom: 12px;
+}
+
+.message-item .message-content {
+ font-family: "Open Sans";
+ color: rgb(89,90,92);
+ font-size: 14px;
+ margin-bottom: 16px;
+}
If you aren't running your app already, do so by executing meteor
in the project's root directory and make sure your app looks like the screenshot in the beginning of this chapter. Also, you may want to keep two Terminal windows open from now on - one to keep the Meteor server running, and one to manage your app's directory structure.