Created
August 15, 2012 01:04
-
-
Save vidoss/3354438 to your computer and use it in GitHub Desktop.
Backbone for server rendered markup!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This Gist is for the case where your html is generated on the server side, but you still want to use Backbone to manage | |
the incremental user actions. The idea is to parse the already rendered DOM and create the model / collection on the | |
first time, hence we can still follow the Backbone pattern to update models and the bindings reflect view and update server etc. | |
Lets do step by step for the infamous TODO application: | |
Step 1) Add a function dom2coll() to the AppView that will parse the rendered DOM and convert to data. | |
dom2coll: function() { | |
// To update model/view from already rendered DOM from backend. | |
return _.toArray(this.$("#todo-list li").map(function(idx){ | |
return { | |
id: $(".view",this).data("id"), // from <div data-id="xyz" attribute in server markup. | |
title: $(".view label",this).text(), | |
done: $(this).hasClass("done"), | |
order: idx, | |
el: this // pass el as well. | |
} | |
})); | |
}, | |
// In the initalize() of TodoApp change the fetch() to.. | |
initialize: function() { | |
... | |
Todos.fetch({dom2coll: _.bind(this.dom2coll,this)}); | |
... | |
} | |
Step 2) Override the "sync" in the TodoList to call above function, instead of going to server. | |
This way your model is clean of view specific details. | |
sync: function(method, model, options) { | |
// If no dom2data go the default route. | |
if (!_.isFunction(options.dom2coll)) { | |
return Backbone.sync.apply(this, arguments); | |
} | |
// update from already rendered DOM. | |
options.success(options.dom2coll()); | |
} | |
Step 3) Modify addOne() in the AppView to not call append(view.render().el) when el already exists. | |
Pass "el" in the TodoView() constructor. | |
addOne: function(todo) { | |
var el = todo.get('el'), | |
attrs = {model: todo}; | |
if (el) { | |
attrs["el"] = el; | |
todo.unset('el',{silent: true}); // unset - so model will be clean. | |
} | |
var view = new TodoView(attrs); | |
if (!el) { | |
// skip appends for doms already rendred. | |
this.$("#todo-list").append(view.render().el); | |
} | |
}, | |
DONE! Now all the views and model objects are ready and events delegated. No append, No insert, No innerHTML. clean! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I prefer server side rendering for a simple reason. The rendering code is running on a machine I have more control over.