Skip to content

Instantly share code, notes, and snippets.

@vidoss
Created August 15, 2012 01:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vidoss/3354438 to your computer and use it in GitHub Desktop.
Save vidoss/3354438 to your computer and use it in GitHub Desktop.
Backbone for server rendered markup!
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!
@pspeter3
Copy link

Just out of curiosity would you be forced back to server side rendering?

@vidoss
Copy link
Author

vidoss commented Aug 15, 2012

I prefer server side rendering for a simple reason. The rendering code is running on a machine I have more control over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment