Organizing Handlebars Templates in NodeJS with Jade Partials

I’ve been banging my head against the wall trying to learn Backbone.js. My usual process for learning a new technology or framework is to try to do things the ugliest way possible to get it working, and then refactor and spot patterns to organize things. One of the most frustrating pieces of my stack right now are my handlebars templates, which started out lumped into a bunch of <script> tags at the top of my page.

For those of you that have tried working with Handlebars before, you’re probably more than familiar with blocks of {{code}} like this stuck into your <head> tag:


// Report - Sales Tax
script(type='text/x-handlebars-template', id='salesTax-template')
  h1 Sales Tax
  {{#each report}}
  {{#dates}}
  h3 Start Date:
    {{start}}
    | End Date:
    {{end}}
  {{/dates}}

  {{#totals}}
  h2 Totals:
  p Services:
    {{services}}
  p Products:
    {{products}}
  {{/totals}}

  h2 Tax:
  {{#tax}}
  p Services:
    {{services}}

  p Products:
    {{products}}
  {{/tax}}
  {{/each}}

I was really frustrated with these files cluttering up my layout.jade file in my root directory, because I need to deliver the templates when I first load the Backbone app. I’ve read a ton about how to split Handlebars templates into their own files using Backbone, but haven’t seen any decent solutions, so I set out to solve it using other tools in my stack.

The (ridiculously simple) solution I came up with was to use Jade partials on my NodeJS server so that with the initial pageload, Jade would compile all of the templates into one main HTML file and serve it to the client! Easy.

So here’s the code I’ve got in my layout.jade:


// Handlebars Templates - move these to separate files eventually
!=partial('templates/reports')
!=partial('templates/reports/salesTax')
!=partial('templates/reports/newClients')
!=partial('templates/reports/selectStylist')

The !=partial command searches the views directory for any files matching the path/filename you specify ending in .jade. For example, I’ve used the folder ./templates and placed all of the templates for my reports under ./templates/reports. The base template that acts as a container for my other report templates is called index.jade and is called on the first line. The rest of the templates are for individual report templates.

Finally, I’ve included the following code in my initialize() function for each of my Views to render the templates.

reportView.coffee:


### Reports - Base collection for all reports ###
class window.Reports extends Backbone.Collection
  model: Report

# Overall report master view!
class window.ReportView extends Backbone.View
  initialize: ->
    @el = $('.containerOuter')
    _.bindAll this, 'render'

    # Compile Handlebars template at init
    # (Not sure if we have to do this each time or not)
    source = $('#report-template').html()
    @template = Handlebars.compile source
    @render()

  render: ->
    renderedContent = @template { }
    $(@el).html renderedContent

  • http://twitter.com/changtimwu Tim Wu

    I use handlebars in ember.js.  This helps me a lot.  Thanks.  I found that Jade can do client side JS templating and its template syntax is more elegant than others(IMO).  Have you tried it?

    • http://braddickason.com/ Brad Dickason

      Hey Tim, glad you found this helpful! I’ve been meaning to play around with ember.js but haven’t had a chance yet. My suggestion would be to avoid using Jade on the client-side, only because it’s not really readily supported. I looked into going this route as well and the number of people using Handlebars on the client is roughly 100x the number of people using Jade on the client.

      From a technical standpoint, however, it’s totally doable.

    • http://braddickason.com/ Brad Dickason

      I messed around ab it with Jade client side and wasn’t thrilled with the results. I found it too complex and arduous to pass the templates around. Now that Express 3.0 is out, however, I may revisit as I generally trust all things TJ :)

  • Ben

    Another option would be to use script tag during development and ship the templates pre-compiled as javascript for deployment.. 

    http://handlebarsjs.com/precompilation.html

  • Tim Robinson

    Thanks for the tutorial, what do you do now that partials have been removed in Express 3.0?

    • admin

      To be honest, I just started using Express 3.0 today. Will try to mess around with this next week at some point.

    • http://braddickason.com/ Brad Dickason

      Hey Tim, glad you found this helpful! I’ve been meaning to play around with ember.js but haven’t had a chance yet. My suggestion would be to avoid using Jade on the client-side, only because it’s not really readily supported. I looked into going this route as well and the number of people using Handlebars on the client is roughly 100x the number of people using Jade on the client.
      From a technical standpoint, however, it’s totally doable.

  • mikesmullin

    I wanted to reiterate Tim Robinson’s question: in the latest express 3.0 + jade we now use Extend and Block in the partial templates; this effectively makes it difficult to convert the jade templates directly to reusable jst/handlebars partial templates without including the whole layout around them, or not using layouts. have you run into this yet?

    • http://braddickason.com/ Brad Dickason

      I just started experimenting with Jade and Express 3.0 this week. I should be in a place to test it out within the next two weeks or so, depending on schedule.

  • mikesmullin

    as a follow-up, towerjs.org does what we all want here.