marionettejs/backbone.marionette — pull request #426 by brettjonesdev (2013-01-21 00:44:04+00:00)
Title: Added view parameter to Renderer.render()

I am currently working on a Marionette boilerplate project in which I use AMD/Require.js and Handlebars templating. I do not intend to use the Marionette TemplateCache mechanism; rather, my template methods are pulled in from separate files using the Require text plugin, like so:

define( ['jquery', 'handlebars', 'text!templates/welcome.html'],
function($, Handlebars, template) {
return Backbone.Marionette.ItemView.extend( {
template: template
});
});

At the same time, I am overridding the Backbone.Marionette.Renderer.render() method to encapsulate some simple default templating.

One goal I had in mind was for the Renderer.render() function to be able to work whether view.template was a templating function OR a template string, and if it was a string, then after compilation via Handlebars (or _.template() ), to save the compiled template function as the view.template item. That way, the compilation of a view's template would only occur the first time it is rendered.

In order for this to work, though, I need the render() method to be passed a reference to the view which is being rendered, in order to save off the template function onto the view. A secondary benefit to having this information available at render-time is that a view may have an attribute which serves as a switch to determine what templating engine to use. I find this helpful in projects where I wish to use Handlebars at most times with the exception of particularly complex views, for which something more feature complete such as _.template() is appropriate. In my case, I wish to have a view._engine attribute which can be used in the render() method to determine which templating engine to use.

My goal can be accomplished with three simple changes:

marionette.renderer.js

add a view parameter
render: function(template, data, view){

marionette.itemview.js

pass a reference to the view
var html = Marionette.Renderer.render(template, data, this);

marionette.compositeview.js

pass a reference to the view
return Marionette.Renderer.render(template, data, this);

With these changes, it is possible for a user to write a custom render() method which can implement a custom template caching scheme, such as this example from my project:

Marionette.Renderer.render = function (template, data, view) {
var templateFunc;
if ( !view ) view = { _engine: 'Handlebars' };
if (typeof template === 'function') {
templateFunc = template;
} else if (typeof template === 'string') {
if (view._engine === 'underscore') {
templateFunc = _.template(template);
} else {
templateFunc = Handlebars.compile(template);
}
// cache the templateFunc on the view to prevent recompilation next time
view.template = templateFunc;
view.options.template = templateFunc
}
var html = templateFunc(data);
return html;
};

Since this solution is really just passing along a parameter which is already available, introducing this change should be completely harmless. Having the view available in the render() method will allow Marionette.Renderer to become much more flexible and powerful for users looking to encapsulate custom rendering logic therein.

This is my first pull request ever, so please forgive me if this is not formatted as well as it could be. Let me know what you think! I would love to help make an already great library even better.

- Brett Jones