38

Im getting into Backbone.js to structure the javascript code for my project and I love HAML for templating on the backend(rails), so Id like to use it for Backbone Views templating. I know there is several HAML ports to Javascript, like https://github.com/creationix/haml-js and backbone supports JST and mustache with ease.

Whats the best way to use haml templating instead.

Are there any downsides to using HAML on the client side? Performance, extra script load time(taken care by asset packaging tools like jammit)

Vlad Gurovich
  • 8,463
  • 2
  • 27
  • 28

8 Answers8

26

I know you already mentioned it but I would suggest using haml-js with Jammit. Simply include haml.js in your javascripts and in your assets.yml add template_function: Haml as well as including your template files in to a package. e.g.

  javascript_templates:
    - app/views/**/*.jst.haml

Then in your views you can include this package (= include_javascripts :javascript_templates) and Jammit will package any .jst.haml files in to window.JST['file/path']. (If you view page source you should see a javascript file like <script src="/assets/javascript_templates.jst" type="text/javascript"></script>)

To use these templates simply call one of those JSTs Jammit created. i.e.

$('div').html(JST['file/path']({ foo: 'Hello', bar: 'World' }));

And Jammit will use the Haml-js template function function to render the template.

Note: Be sure to point to the github repo of Jammit in your Gemfile to get the latest version that supports newline characters necessary for haml-js to work.

Craig
  • 540
  • 5
  • 14
  • The issue of [Jammit not supporting newline characters](https://github.com/documentcloud/jammit/issues/127) has been solved and should be included in the next release. – rubiii Apr 10 '11 at 15:09
  • Is there a tutorial for using .jst files? I don't unserstand how you would use them after they have been packaged. I'm used to doing `$("#template_name").tmpl(data,helper)`. How would you get a hold of the templates packaged by jammit? – picardo Apr 10 '11 at 18:35
  • I elaborated on my original answer. Let me know if that helps. – Craig Apr 22 '11 at 16:31
14

I'm about to give haml-coffee a shot. (no pun intended) I can't sing the praises of coffeescript enough; plus it's a default now in Rails 3.1. Now I can embed coffeescript within my favorite templating language, and pre-compile the lot.

Oh, the joy.. now to get it to work.

Duke
  • 7,070
  • 3
  • 38
  • 28
  • 2
    I gave [haml-coffee](https://github.com/9elements/haml-coffee) a lot of love lately and made it fully HAML compliant. In addition I created [haml_coffee_assets](https://github.com/netzpirat/haml_coffee_assets) for using haml-coffee templates in the Rails 3.1 asset pipeline. – Netzpirat Nov 25 '11 at 16:27
  • 3
    This is now much better than the 'official' answer, seeing as how it works out-of-the-box with the asset pipeline (as far as I've been able to tell?). I've only been playing with it briefly but so far this looks like exactly what I needed. Plays nice with Backbone, Haml, Coffeescript, asset pipeline. Love it! – nzifnab Mar 22 '12 at 20:30
6

I know this would somewhat going around the question but here we go :)

I my rails app I use haml for all views on the backend. It is awesome. For some reasons (mainly i18n), I do not like to use templates on the client side. This is how I do it:

  • create all your template in ruby haml and store them into script tag with a funky type (i use text/js-template). This will create prerendered html that you can play with with jquery and backbone.
  • when you create your backbone views, load the stored template and append it to your document
  • Render your view by altering the preexisting template

You deal only with html and jQuery is awesome for that. For some views that do not requires i18n, I use underscore templating because it's already there.

As for haml templating performance, it seems mustache and handlebars are faster.

Julien
  • 9,216
  • 4
  • 37
  • 38
  • 1
    Ive used this strategy before where i would store a prerendered html template in a hidden element inside my html and would clone it and populate it with data, but its an ugly and not DRY code, hence my interest in templates. I like logicless premise of mustache, but I LOVE HAML syntax. I hope there is a way to use it on client somehow – Vlad Gurovich Mar 10 '11 at 20:19
  • Wouldn't your templates for AJAX be the same as writing them for a partial? – rxgx Mar 16 '11 at 03:34
2

I've been working on Rails 3/Backbone app and have taken a different approach after evaluating hamlbars, haml_assets, and playing around with haml-js.

These are all solid gems which offer solutions to the problem, each having a certain set of trade-offs. Haml-js, for instance, requires rendering templates client side (there's nothing wrong with this, it's simply a tradeoff). Hamlbars and haml_assets both plug into the asset pipeline but because they exist outside of the request object some helpers will not work. Both make some adjustments for this and include url helpers and ActionView helpers, but don't expect to have the same features as writing haml in a view.

My approach is somewhat bulky (I am planning on putting this into an engine) but it works well and easily replicable. It uses haml_assets when possible, but falls back on serving a template from a "templates" controller with a "show" action

  • Put your views in the view/templates/ directory
  • You can add a layout that renders this view into a JST function
  • You can specify the show action to return "application/javascript" as its content type
  • You have access to all helpers when writing templates
  • You can add script tags for "/template/whatever" that will render the whatever template, or use route globbing for better organized views.

The benefit of this approach is that because your views are accessible from controllers, you have the option to render them as jst templates (via the templates controller) or via other controllers as partials. This would allow you to serve seo-friendly pages directly from url's (like /products/widgets/super-cool-widget) were users may get the cached templated /templates/widgets/super-cool-widget.

mhamrah
  • 9,038
  • 4
  • 24
  • 22
1

I can't answer inline on Craig's thread (I'm guessing I need some sort of reputation to post on existing answers), but you no longer need to grab a fork of jammit to use haml-js -- the commit made it into the main branch of jammit. See here for details: https://github.com/documentcloud/jammit/commit/b52e429f99cac3cd1aa2bf3ab95f1bfaf478d50d

EDIT: the last gem release was in Jan, and the commits were added in March, so you'll need to set up bundler to run against the github repo or build it locally. If you don't use HEAD of jammit you'll have trouble getting the templates to be parsed properly since the newlines are stripped.

All I needed to do to set this up is:

1) Add the following to my "assets.yml" file:

template_function: "Haml"

2) Add the haml-js source and templates I wanted to load to my assets file: javascripts: core: - public/javascripts/vendor/haml.js templates: - app/views/events/_form.haml.jst

3) Make sure I was loading both core and templates in my application.html.erb

<%= include_javascripts :core, :templates %>

4) Access templates in my source files via JST[filename] (ie, in this case JST['_form']). One gotcha worth mentioning -- jammit will look at all your templates and namespace them down to the common path, so if you have app/views/foo/file.jst and app/views/bar/file.jst, you'd access with JST['foo/file.jst'] and JST['bar/file.jst']. If you had app/views/foo/file1.jst and app/views/foo/file2.jst, they'd be directly at JST['file1.jst'] and JST['file2.jst'] -- which is easy to forget when you're starting out with your first few templates.

Everything worked quite nicely. I'm not sure why Craig needed to define a function -- I just used the default Haml function provided by haml.js, but maybe I'm missing something.

mv_house
  • 51
  • 2
  • This is great to know. I think ive seen you on YC discussions of backbone(where i actually learned of it) – Vlad Gurovich Apr 06 '11 at 21:19
  • Thanks for the elaboration. I updated my original post. I created a function originally because I was following the jammit help on using Mustache templates. Didn't realize I could just call Haml directly :-P – Craig Apr 22 '11 at 16:48
0

Looks like https://github.com/netzpirat/haml_coffee_assets gives you what you want. (window.JST templates, written in HAML, with inline coffescript support)

Jordan Warbelow-Feldstein
  • 10,510
  • 12
  • 48
  • 79
0

Check out Middleman. It includes haml, sass, coffee, slim, etc. It uses gems like rails does and has a lot of other awesome functionality.

http://middlemanapp.com/

They even have a custom extension for backbone, https://github.com/middleman/middleman-backbone

It also allows you to build it into static html, css, and js for super fast loading.

Blaine Hatab
  • 1,626
  • 17
  • 24
-3

You could try Express with Jade (Haml-like templates). Express builds on Connect for routing static files. Jade is one of the faster template engines I've tried with Node.js

http://expressjs.com/

  • My question is specifically about HAML and Backbone. – Vlad Gurovich Mar 10 '11 at 02:03
  • I think this article answers your question http://fzysqr.com/2011/02/28/nodechat-js-using-node-js-backbone-js-socket-io-and-redis-to-make-a-real-time-chat-app/ – J. Michael Wilson Mar 10 '11 at 02:06
  • That page doesn't even mention HAML, so I don't think it answers the question. – Alex Korban Mar 10 '11 at 03:15
  • Jade templates use HAML in other words Jade is a port of HAML to javascript – J. Michael Wilson Mar 10 '11 at 03:45
  • Ok, so Jade syntax is similar to HAML, that's fine. Whats missing, even in the last link you posted is how to have Backbone Views render JADE/HAML templates that are SPECIFIC to these views/models – Vlad Gurovich Mar 10 '11 at 05:29
  • OK, I guess that was a pretty large article, so I shouldn't have expected you to read all of it. It gives a pretty good step by step example of how the author went about binding the models > to views > to jade templates. Views our bound to elements via a custom class object called Backbone.View.extend, in other words > var custom_class = Backbone.View.extend({...}); The object has properties and methods that bind to tag names, class names, or #ids. So, you see it doesn't depend on any template engine, just how you choose to define and select your html. – J. Michael Wilson Mar 10 '11 at 10:49
  • @JMichealWilson your missing the big difference between running a `node.js` back end and a `RoR` back end. As much as I love recommending that one uses node, this question is about rails. – Raynos Mar 10 '11 at 16:52
  • 2
    @Raynos I see what you mean, my mistake. I assumed it wasn't a different issue if implementing Backbone in Rails. Sorry everyone, I guess that wasn't too helpful :O – J. Michael Wilson Mar 10 '11 at 17:07