I had planned on moving onto to model relations today, but... While trying to finish off the underscore.js chapter for Recipes with Backbone, I came across a bit of a conundrum.
I really hate ERB syntax, which is the default in underscore templates:
<div class="previous"> <a href="#month/<%= previous_date %>">previous</a> </div> <div class="next"> <a href="#month/<%= next_date %>">next</a> </div>Embedding pseudo-HTML tags inside real tags hurts my eyes.
I much prefer the mustache style syntax:
<div class="previous"> <a href="#month/{{ previous_date }}">previous</a> </div> <div class="next"> <a href="#month/{{ next_date }}">next</a> </div>It is much easier to pick out the variables to be interpolated because mustache uses different delimiters than plain old HTML.
Happily, underscore makes it easy to change the template interpolation scheme. I only need to change
_.templateSettings
: _.templateSettings = {
interpolate : /\{\{([\s\S]+?)\}\}/g
};
The trouble is, not everyone agrees with me. There are deluded people out there who might actually prefer ERB. I think the only explanation can possibly be that they simply don't know any better, but who knows? Maybe there really is a legit reason.Actually, no. There isn't.
Anyhow, no matter what my personal feelings are, I must play nice with others. If I am writing a library for reuse or want to use libraries that might employ ERB under the covers, I cannot make changes to
_.templateSettings
without fear of breaking other code.Happily, that is not a problem. Inside my
Views
namespace closure, I define a template()
helper function. This helper squirrels away the global value of _.templateSettings
, applies sane settings, and then restores the previous settings: function template(str) {
var orig_settings = _.templateSettings;
_.templateSettings = {
interpolate : /\{\{([\s\S]+?)\}\}/g
};
var t = _.template(str);
_.templateSettings = orig_settings;
return t;
}
Now, when I am building my template function in my views, I can use this helper method so that I get my nice, mustache-y syntax: var CalendarNavigation = Backbone.View.extend({
initialize: function(options) {
this.collection = options.collection;
},
template: template(
'<div class="previous">' +
'<a href="#month/{{ previous_date }}">previous</a>' +
'</div>' +
'<div class="next">' +
'<a href="#month/{{ next_date }}">next</a>' +
'</div>'
),
render: function() {
var date = this.collection.getDate();
$(this.el).html(this.template({
previous_date: Helpers.previousMonth(date),
next_date: Helpers.nextMonth(date)
}));
return this;
}
});
With that, I have my lovely mustache style templates generating my navigation HTML:And, poor lost souls can continue to use ERB:
Hopefully that finishes off my underscore templating exploration. I really am keen to move onto model relations.
Day #188
I just wanted to post some information for anyone else that needed to do this. I was using this method that Chris described and it worked well until I needed to integrate this with some other views. The settings wouldn't return to the original state after calling _.template()
ReplyDeleteHowever, I was digging into the underscore code and noticed that you can pass settings to the function and it works as a temporary call as mentioned above.
Could be that underscore has updated a lot over the past year and it's "new" anyway, to do this now you'll want to do something like this:
template: _.template( $('#your_template').html(), null, { interpolate : /\{\{([\s\S]+?)\}\}/g };),
ofcourse it will not work, because he tries to copy an object simply by save it in a variable. But what he actually do is that he creating another variable that links to the SAME OBJECT.
ReplyDeletevar orig_settings = _.templateSettings;
lol