Handlebars.js Conditional Trick

15 Mar 2015

The other day I was working on generating a handlebars template from an object of objects and came across a small but annoying issue. I needed to create a list of items, and each item template needed to be slightly different. Since handlebars conditionals only check a variable for being true, we can't use operators to divide the items into little "subtemplates".

For instance, let's say we have an object of menu items divided up into three types that each need a slightly different handlebars template.

Ideally, I would pass that object into a template like this:

    {{#if foodType == entree}}
        <span class="meal entree">{{ name }}</span>
    {{else if foodType == drink}}
        <span class="meal drink">{{ name }}</span>
    {{else if foodType == dessert}}
        <span class="meal dessert">{{ name }}</span>
    {{/if}}

Unfortunately this isn't an option with vanilla handlebars, instead you can only test a property's truthfulness, like:

    {{#if entree}}

    {{else if drink}}

    {{else if dessert}}

    {{/if}}

As an example, let's use this JSON response as the data we want to use for our template.

    var Obj = {
        mealItem {
            foodType: "entree",
            name: "steak",
            price: "30.00",
        },
        mealItem {
            foodType: "dessert",
            name: "cake",
            price: "4.00",
        },
        mealItem {
            foodType: "entree",
            name: "chicken",
            price: "10.00",
        }
        mealItem {
            foodType: "drink",
            name: "orange juice",
            price: "2.00"
        }
    }

If we want our menu item template to be populated by these mealItems in our object then appended to a div, we can send them through like this:

    for (var i = 0; i < Obj.length; i++) {
        Obj[i][foodtype] = true; // creates a new property named what the foodType property contains

        // Send updated item object through handlebars template
        var template = Handlebars.templates.foodItems(Obj[i]);
        $("container").append(template);
    }

Now each mealItem will be passed to the template with it's food type as a property, so we now use it in our handlebars conditionals without forcing handlebars to fit our data.

    {{#if entree}}

    {{else if drink}}

    {{else if dessert}}

    {{/if}}