All posts tagged handlebars

  • Using Handlebars Templates With Backbone and Browserify

    While working on a recent side-project, I ran into some trouble implementing Handlebars templates for my use in my backbone views when using Browserify for my dependency management. If you’ve run into similar issues, here’s a quick breakdown of what you’ll need to do to get up and running again:

    1. Install Hbsfy

    In order to precompile the templates for use in your app, you’ll need to install hbsfy and include it in your gulpfile. For the record, I have no idea what the hell that’s supposed to stand for but I like to imagine it being short for “Handlebars Sci-Fi” but spelled in the same way as the terrible TV network. Here’s a snippet from my gulpfile for you to use as a starting point.

        var gulp,
            browserify,
            del,
            gulp,
            hbsfy,
            sass,
            source,
            sourcemaps;
    
        gulp = require('gulp'); // Include gulp
    
        // Include our plugins
        browserify      = require('browserify');
        del             = require('del');
        hbsfy           = require("hbsfy"); // <---- THIS RIGHT HERE
        sass            = require('gulp-sass');
        source          = require('vinyl-source-stream');
        sourcemaps      = require('gulp-sourcemaps');
        //---
    ...
    

    Apply Hbsfy During the Bundle Process

    Once you’ve included Hbsfy, you’ll need to apply it as a transformation during the bundle() process:

    ...
        gulp.task('compile', function () {
            var options;
    
            options = {
                debug: true,
                paths: [
                    './node_modules',
                    './src/app/'
                ]
            };
    
            hbsfy.configure({
                extensions: ['hbs']
            });
    
            browserify('./src/main.js', options)
                .transform(hbsfy)
                .bundle()
                .pipe(source('app.min.js'))
                .pipe(gulp.dest('build/public/assets/js'));
        });
    ...
    

    The one thing to note in the above snippet is the call to hbsfy.configure where I am simply telling hbsfy (I seriously want to know what that stands for) that my template files will all end in .hbs. You can substitute in whatever file format you’re using for your templates.

    3. Include the Template in the Same File As Your Backbone View

    Once you’ve got your gruntfile configured properly, you can safely start using Handlebars templates in your Backbone views…almost. You still need to include them. It’s rather straightforward:

    (function () {
        'use strict';
    
        var User,
            Users,
            Handlebars,
            template,
            Backbone;
    
        Backbone = require('backbone');
        User = require('entities/user');
        Users = require('collections/users');
        Handlebars = require('handlebars');
        template = require('./search-full.hbs'); // <!-- RIGHT HERE
    ...
    

    4. Override the Render Method of Your View and Call the Template

    ...
        module.exports = Backbone.View.extend({
            className: '.form',
            el: '#app',
            events: {
                'keypress .search .field': 'submitSearch'
            },
            initialize: function () {
                this.render();
            },
            render: function () { // <!-- OVERRIDDEN
                this.$el.html(template());
                return this;
            },
    ...
    

    For the record, I’m not sure if this is the way to do this. However, I tried simply setting the value of the template property on the view and it didn’t work. If you know of a better way, feel free to leave a comment.

    Wrapping Up

    Well, I hope this eased someone’s frustrations out there. If it did or if you know of a better approach to this problem, please let me know in the comments below.

  • How to Exclude Layout Files When Rendering Templates With Node.js and Express

    I struggled with this for a good half-hour and I figured I’d share in case anyone else ran into this issue. Long story short, I needed to return an HTML fragment for a particular ajax request from the app (in this case, search results) but the response always included the layout file I configured for the app:

        hbsEngine = expressHbs.create({
            extname: 'hbs',
            defaultLayout: 'layout.hbs',
            helpers: {
                formatDate: function (date, format) {
                    return moment(date).format(format);
                }
            }
        });
    

    Read more

  • Formatting Dates Using Moment.js, Handlebars, Express, and Node.js

    For those of you out there that may be struggling with this, here’s a quick breakdown of how to format dates using moment.js, handlebars, express, and node.js. This post assumes you have the following packages installed in your express app:

    1. Express3 Handlebars (link)
    2. Moment.js (link)

    Once you’ve included these packages in your app.js file, you’ll need to set up handlebars like so:

    ...
    app = express();
    hbsEngine = expressHbs.create({
        extname: 'hbs',
        defaultLayout: 'layout.hbs',
        helpers: {
            formatDate: function (date, format) {
                return moment(date).format(format);
            }
        }
    });
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.engine('hbs', hbsEngine.engine);
    app.set('view engine', 'hbs');
    ...
    

    You can ignore the extname and defaultLayout configs incase you want to use the default values that handlebars sets for you for the extension and layout file name. The important thing to note is the helpers object. Basically, it’s the equivalent of the registerHelpers method in the JS version of Handlebars. In this example, I’m create a formatDate method that takes in a date and “format“ string and returns a formatted date via moment.js.

  • Creating New Conditionals in Handlebars

    If you work with Handlebars long enough, you’ll start to notice a very annoying gap in its capabilities: conditionals. Now, Handlebars does come with a conditionals helper that simply tests whether or not the passed in value is truthy or not and acts accordingly. While this is fine for a good portion of scenarios, I guarantee there will come a time where you need a more robust solution. Today, we’re going to go over three conditional helpers that handlebars is lacking and how to make them yourself.

    EqualTo

    Handlebars.registerHelper('ifequal', function(value1, value2, options) {
      if(value1 === value2) {
        return options.fn(this);
      }
      return options.inverse(this);
    });
    

    LessThan and LessThanOrEqual

    Handlebars.registerHelper('iflessthan', function(value1, value2, options) {
      if(value1 < value2) {
        return options.fn(this);
      }
      return options.inverse(this);
    });
    
    Handlebars.registerHelper('iflessthanorequal', function(value1, value2, options) {
      if(value1 <= value2) {
        return options.fn(this);
      }
      return options.inverse(this);
    });
    

    If you need additional functionality (e.g., greater-than-or-eaual-to or not-equal-to), you can easily figure out what needs to be done given the examples provided. If you don’t feel like creating individual helpers for each kind of conditional, I found this really cool snippet on StackOverflow that may come in handy:

    Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
    
        switch (operator) {
            case '==':
                return (v1 == v2) ? options.fn(this) : options.inverse(this);
            case '===':
                return (v1 === v2) ? options.fn(this) : options.inverse(this);
            case '<':
                return (v1 < v2) ? options.fn(this) : options.inverse(this);
            case '<=':
                return (v1 <= v2) ? options.fn(this) : options.inverse(this);
            case '>':
                return (v1 > v2) ? options.fn(this) : options.inverse(this);
            case '>=':
                return (v1 >= v2) ? options.fn(this) : options.inverse(this);
            case '&&':
                return (v1 && v2) ? options.fn(this) : options.inverse(this);
            case '||':
                return (v1 || v2) ? options.fn(this) : options.inverse(this);
            default:
                return options.inverse(this);
        }
    });
    

    You use it like this:

    {{#ifCond var1 '==' var2}}