Blog of Lukas White, Manchester-based Web Developer specialising in PHP, Drupal and Laravel

Building Applications with Backbone and Laravel: JST

You might well be used to developing Backbone views like this:

 MyApp.Views.SomeView = Backbone.View.extend({    
  template: _.template('<ul><% _.each(items, function(item){ %><li><%= item %></li><% }); %></ul>'),    
  el: '#some-element',

This is all fine and well for simple structures, but can quickly get unwieldly if you're building markup of any significant size or complexity. It can also lead to all sorts of issues around readability.

One alternative is to put more complex templates into separate HTML files:

// file: folder/template.html
 
<ul>
 <% _.each(items, function(item){ %>
 <li><%= item %></li>
 <% }); %>
</ul>

Each time you want to render a template, you can load in the template via AJAX or use RequireJS's text plugin. Great for development, but pretty atrocious for performance, as it'll fire off untold numbers of HTTP requests.

Using JST allows you to develop templates in this way - spreading templates across separate files, organised into a logical hierarchy - but "collapse" them into variables which are available via a single JS file. This file can then be minified, or incorporated into a larger Javascript file using, for example, the RequireJS optimiser or Google Closure Compiler.

Such a file looks a little like this:

// file: jst.js
 
var JST = JST || {};
JST['app/templates/folder/template.html'] = _.template('<ul><% _.each(items, function(item){ %><li><%= item %></li><% }); %></ul>');
JST['app/templates/folder/template2.html'] = _.template('...');
JST['app/templates/folder2/template.html'] = _.template('...');
// etc...

JST and Laravel

If your Backbone application's back-end uses Laravel, I've written a package to generate such a file.

Usage

Generate your JST file by entering the following command in your terminal:

php artisan jst:generate

Or alternatively, you can have it "watch" your templates directory (and any sub-directories) for changes, and recompile the file for you:

php artisan jst:watch

Back to your Backbone application:

// file: namespace.js
 
define([
    // Libs
    "jquery",
    "use!underscore",
    "use!backbone"
],
 
function($, _, Backbone) {
 // Put application wide code here
 
 return {
  // This is useful when developing if you don't want to use a
  // build process every time you change a template.
  //
  // Delete if you are using a different template loading method.
  fetchTemplate: function(path, done) {
   var JST = window.JST = window.JST || {};
   var def = new $.Deferred();
 
   // Should be an instant synchronous way of getting the template, if it
   // exists in the JST object.
   if (JST[path]) {        
    if (_.isFunction(done)) {
     done(JST[path]);
    }
 
    return def.resolve(JST[path]);
   }
 
   // Fetch it asynchronously if not available from JST, ensure that
   // template requests are never cached and prevent global ajax event
   // handlers from firing.
   $.ajax({
    url: path,
    type: "get",
    dataType: "text",
    cache: false,
    global: false,
 
    success: function(contents) {
     JST[path] = _.template(contents);
 
     // Set the global JST cache and return the template
     if (_.isFunction(done)) {
      done(JST[path]);
     }
 
     // Resolve the template deferred
     def.resolve(JST[path]);
    }
   });
 
   // Ensure a normalized return value (Promise)
   return def.promise();
  },
 
 };
});

As you can see, this provides a method which tries to load a template from a global variable called JST, but if that's not available - i.e., during development - then it loads it in as an HTML file using AJAX.

Now you can create a view like this, to take advantage of it:

MyApp.Views.SomeView = Backbone.View.extend({
 template: "app/templates/folder/someview.html",        
    render: function(done) {      
  namespace.fetchTemplate(this.template, function(tmpl) {        
   view.el.innerHTML = tmpl({model: view.model.toJSON() });
   if (_.isFunction(done)) {
    done(view.el);
   }  
  });
 }
// …

Using it Outside of Laravel

There's no reason why this code can't be re-purposed to work outside of Laravel - perhaps I'll get a chance at some point, but feel free to have a stab at it. All the dependencies are managed via Composer.

More Articles and Tutorials

I've had a few more articles and tutorials published in the past few days, with a number to come later this month. Here's a quick run-down of the articles I've had published in the past couple of weeks.

Abstract File Systems with Flysystem, Sitepoint

An introduction to Flysystem, a PHP library which provides developers with a layer of abstraction over file storage systems including standard local files, online services such as Dropbox and Cloud Files and remote storage mechanisms such as FTP.

Introduction to JadePHP, Sitepoint

Jade is a templating language often found in the JavaScript world. Heavily influenced by Haml, it provides an extremely concise way of defining your XML-based markup. JadePHP brings it to PHP, and in this article I take it for a test-drive.

Getting Started with Assetic, Sitepoint

Assetic is an asset management package for PHP. It helps organise static assets - such as stylesheets, javascript and images - and perform actions on them such as compilation, compression and concatenation. In this article, I give a rundown of how to use it.

Coming Up

Here's a sneak preview of what's coming up.

I've written a huge four-part tutorial on using Apache SOLR along with Solarium, a PHP library which allows you to use SOLR as if it were a native search implementation. It's due sometime around the end of April.

Kirby is a very simple, file-based CMS written in PHP. I've written a comprehensive review of it, which will be published in the next couple of weeks.

I've also written extensively on Piwik which is a self-hosted, open-sourced alternative to Google Analytics. If you've been concerned recently with Google and privacy, or simply want to take control of your analytics data, then it's well worth a look.

I've also been doing some writing about Node, which I've been working with a lot lately. One upcoming article is about using JSON web tokens to secure an application, using examples written in Node with Express and Backbone for the server-side and client-side components respectively. I've also written an article on using streams in Node. Both articles should be published in the next few weeks.

Finally, I've also written a thorough review of Brackets, which is an open-sourced editor originally by Adobe.

Keep an eye out for these if they're of any interest - I'll be continually updating this page with the details.

Pages