Backbone.js coding style and best practices

Stating the obvious:

1) Try to use hash tagging and history to connect disparate views as much: you keep them independent from each other this way, and back button compatible. In other words: don’t spawn views programmatically, let the router do the work for you.

2) As much as you can: one view = one template = one model and / or one collection.

3) If your page logic or functionality is too complex to accomplish the above: divide and conquer. Create sub views attached to a manager view, and break down and distribute down the logic that way to the sub-views. Your code per file will be small and manageable this way, and your complexity per view will be simpler, and easier to test and debug. Better to end up with 20 views attached to a main view, than a huge single view loaded with methods and functionality.

4) Beating on the dead horse above: atomize, atomize, atomize. Divide your view in the lowest denomination of packed functionality. That way you can encapsulate events / methods better

5) Associate a model to collections, so the conversion of backend data happens automatically (don’t build collections with no models or default models)

6) If you rerender, before you call html(), call empty(). It will clean up memory from the objects you won’t use anymore. Example: $(this.el).empty().html(mymodel.toJSON());

Backbone.js: event aggregation and AMD

Great pattern to decouple your modules, and still have clean mechanism to communicate between them.

1) Create a generic “Notifier” module:

define([
‘underscore’,
‘backbone’
], function(_, Backbone) {
var notifier = _.extend({}, Backbone.Events);
return notifier;
});

2) In the two + views or models that you want to connect, include the notifier via your AMD arguments:

define([‘jquery’,’underscore’,’backbone’,’notifier’], function ($,_,Backbone,Notifier) {

}

3) Once your notifier is included that way, to subscribe and listen to events, all you have to do now is bind to the events you would like to listen to:

initialize: function () {
Notifier.on(‘helloEvent’, function (e) { alert(‘The main view says: ‘ + e)}, this)
},

4) To trigger events and push them to the notifier (from other modules), you just have to trigger them:

events: {
“click .clickme”: “sendEventOut”
},
sendEventOut: function () {
Notifier.trigger(‘helloEvent’,’I said hello’);
}

That’s it! Now two different views (or models, or collections) can communicate back and forth via triggered events, and even pass arguments between them.

Backbone.js: binding collection resets

this.collection.bind(‘reset’, this.render, this);

This is run in a view, probably in the initialization function. When the collection gets data from backend, it resets. The last “this” indicates context (in this case, it means the render will happen in this view).

Looping through collections:

_(this.collection.models).each(function (result) {
currentNode.append(new CatalogNodeTableView({model: result}).render().el);
});

 

Templates: example of an each iteration

<% _.each(catalogNodes.root.children, function(node) { %>

<% var nodeType; if(!_.isUndefined(node.type)){nodeType = ‘catalog’;} else if(!_.isUndefined(node.childCategoryIds)){nodeType = ‘folder’;} else {nodeType = ‘item’;} %>

<div class=’grid2col last catalogNode’ data-node-id='<%= node.id %>’ data-node-type='<%= nodeType %>’><%= node.name %></div>

<% }); %>