Using conditionals and helpers with Handlebars.js

April 18th, 2012

Last time, we looked at how we can use a JavaScript template, in our case Handlebars.js, to swap out content. But what if we have some content that isn’t going to appear in each of our content blocks? Continuing with the example from the previous post, let’s add weapons to our people array:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
people = [
    // Awesome
    [{
        name: 'James Bond',
        job: 'Spy',
        rating: 'Awesome',
        weapon: 'Walther PPK'
    },
    {
        name: 'Indiana Jones',
        job: 'Archaeologist',
        rating: 'Awesome',
        weapon: 'Whip'
    },
    {
        name: 'Mario',
        job: 'Plumber',
        rating: 'Awesome',
        weapon: 'Fire flower'
    }],
    // Badass
    [{
        name: 'Bruce Wayne',
        job: 'Superhero',
        rating: 'Total badass',
        weapon: 'Batarang'
    },
    {
        name: 'Jason Bourne',
        job: 'Assassin',
        rating: 'Total badass',
        weapon: 'Everything'
    }],
    // Crazy
    [{
        name: 'Nicolas Cage',
        job: 'Actor',
        rating: 'Crazy'
    },
    {
        name: 'The Joker',
        job: 'Criminal',
        rating: 'Crazy',
        weapon: 'Revolver'
    }]
]

And next we need to update our template

1
2
3
4
5
6
7
8
9
10
<script id="template" type="text/x-handlebars-template">
    {{#each this}}
    <div class="box">
        <p><strong>Name:</strong> {{name}}</p>
        <p><strong>Job:</strong> {{job}}</p>
        <p><strong>Rating:</strong> {{rating}}</p>
        <p><strong>Weapon:</strong> {{weapon}}</p>
    </div>
    {{/each}}
</script>

And this will work exactly like it did in the previous example, except we’ll have one problem. Nicolas Cage doesn’t use a weapon, so he’ll just have a blank spot and that will look pretty awful. Lucky for us, we can use a conditional statement to check if something exists and only add that part if it does. So we’ll modify the template to look like this:

1
2
3
4
5
6
7
8
9
10
11
12
<script id="template" type="text/x-handlebars-template">
    {{#each this}}
    <div class="box">
        <p><strong>Name:</strong> {{name}}</p>
        <p><strong>Job:</strong> {{job}}</p>
        <p><strong>Rating:</strong> {{rating}}</p>
        {{#if weapon}}
        <p><strong>Weapon:</strong> {{weapon}}</p>
        {{/if}}
    </div>
    {{/each}}
</script>

Since not everyone has a weapon, we can wrap that p tag in an if statement like this {{#if weapon}}. This is like saying if (weapon) in regular JavaScript. If weapon exists, then add this, if it doesn’t, don’t. Really simple and really useful, this can be used if you want to create templates with content that really varies. We can also take advantage of paths in Handlebars.js, which can be used to make more complicated content more organized.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
people = [
    // Awesome
    [{
        name: {
            first: 'James',
            last: 'Bond'
        },
        job: 'Spy',
        rating: 'Awesome',
        weapon: 'Walther PPK'
    },
    {
        name: {
            first: 'Indiana',
            last: 'Jones'
        },
        job: 'Archaeologist',
        rating: 'Awesome',
        weapon: 'Whip'
    },
    {
        name: {
            first: 'Mario'
        },
        job: 'Plumber',
        rating: 'Awesome',
        weapon: 'Fire flower'
    }],
    // Badass
    [{
        name: {
            first: 'Bruce',
            last: 'Wayne'
        },
        job: 'Superhero',
        rating: 'Total badass',
        weapon: 'Batarang'
    },
    {
        name: {
            first: 'Jason',
            last: 'Bourne'
        },
        job: 'Assassin',
        rating: 'Total badass',
        weapon: 'Everything'
    }],
    // Crazy
    [{
        name: {
            first: 'Nicolas',
            last: 'Cage'
        },
        job: 'Actor',
        rating: 'Crazy'
    },
    {
        name: {
            first: 'The Joker'
        },
        job: 'Criminal',
        rating: 'Crazy',
        weapon: 'Revolver'
    }]
]

I’ve split name into two parts, first and last, which we’re using as an example of how we can use objects to organize our content even more. But if you loaded the page now, it would should something like [object Object]. The content is in there, how do we get to it?

1
2
3
4
5
6
7
8
9
10
11
12
<script id="template" type="text/x-handlebars-template">
    {{#each this}}
    <div class="box">
        <p><strong>Name:</strong> {{name.first}} {{name.last}}</p>
        <p><strong>Job:</strong> {{job}}</p>
        <p><strong>Rating:</strong> {{rating}}</p>
        {{#if weapon}}
        <p><strong>Weapon:</strong> {{weapon}}</p>
        {{/if}}
    </div>
    {{/each}}
</script>

Now if you run the code, it looks exactly like it was before. This doesn’t really make that much sense to do in a simple example like this but it’s a great option to have if you’re working with a more complicated layout and content. But the point of using these templates it to have less code in our HTML and do all the work in our JS file. This is where Handlebars.js helpers come in. Add this code to your JS file:

1
2
3
Handlebars.registerHelper('fullname', function(person) {
    return person.first + ' ' + person.last;
});

We call the registerHelper method and give it a name of ‘fullname’ then we create function where we combine the first and last name. The person variable can be anything, we’re just passing an object to this function. It’ll make more sense when we look at the HTML:

1
2
3
4
5
6
7
8
9
10
11
12
<script id="template" type="text/x-handlebars-template">
    {{#each this}}
    <div class="box">
        <p><strong>Name:</strong> {{fullname name}}</p>
        <p><strong>Job:</strong> {{job}}</p>
        <p><strong>Rating:</strong> {{rating}}</p>
        {{#if weapon}}
        <p><strong>Weapon:</strong> {{weapon}}</p>
        {{/if}}
    </div>
    {{/each}}
</script>

Instead of {{name.first}} {{name.last}}, we have {{fullname name}}. We’re passing name to our helper and getting Handlebars,js to do all the work of combining the names for us. Helpers are another one of those features that will make your like a lot easier when you’re using far more complex and varied content than we are here, it will keep your template simple and easier to use and put all the heavy lifting in the JavaScript.

You can check out the demo.

That’s all I have about JavaScript templates. Use them any time you can because they will make your coding easier and allow you to work a lot faster.

Leave a Reply

Your email address will not be published. Required fields are marked *