7
votes

When using backbone.js and the companion templating engine in underscore, I've noticed that most examples call model.ToJSON() when rendering instead of just passing model. I understand that my template would have to modify how it retrieves data.

I'm wondering why & what benefit do we get from toJSON()?

Typical Example

In the typical example model.toJSON() is called when rendering. Note, for the sake of brevity, i put the template in as a string literal.

ToDoItemView = Backbone.View.extend({
   /* other viewey stuff */
   template : _.template( '<li><%=ToDoNote%></li>'),
   render   : function () {    
                   var out=  this.template(this.model.toJSON()); //<--JSON
                    $(this.el).html( out) }
                    return this;
                 }
 }); //end view

An Alternate Method

I dug through the backbone 0.9.2 & underscore 1.3.3 code. In backbone, noticed that model.toJSON() does the following: _.clone(this.attributes). Inside the template rendering engine, my compiled template names the passed-data obj.

After seeing those snippets, I realized that cloning the attributes isn't necessary. Instead, I can directly pass in my model (albeit, with some syntax changes in the template). Something like ...

ToDoItemView = Backbone.View.extend({
   /* other viewey stuff */
   template : _.template( '<li><%=obj.get('ToDoNote')%></li>'), //<--notice GET()
   render   : function () {    
                   var out=  this.template(this.model);  //<-- look ma no json
                   $(this.el).html( result ) }
                   return this;
                 }
 }); //end view

Looking at the two examples, the only reasons I can come up with to call toJSON are :

  • protect model data from a nefarious view
  • the view locally modifies data (not a good idea in my opinion),
  • view needs to access values using array/string syntax( obj[ namepart + someindex])

My question boils down to : why would I call toJSON() and take the hit for cloning the properties, rather than just use get() in my templates?

2
"the hit for cloning"? You think that calling get is free?mu is too short
@muistooshort -- Free? no. Get() does return this.attributes[attr];. So is an array lookup faster than an array clone? Yes--from both a resource & time aspect, but that misses my point. Calling toJSON() is clearly built into the backbone communities collective thinking. I'm curious why.EBarr
"Repeated function calls and object accesses" versus "one clone and repeated object accesses" and I don't see any benchmark results so your Yes is merely opinion (just like all the answers are going to be, hence the "not constructive" vote). Not every view is going to be a direct mapping of a model or collection, toJSON is more flexible and reduces the noise in your template.mu is too short
Sorry you seem angry about this. Your reason about "not necessarily direct mappings" is a good constructive answer.EBarr
I'm not angry, comments need to be brief and I don't think this sort of discussion belongs here, nothing personal.mu is too short

2 Answers

12
votes

Maybe the following makes sense:

  1. Interpolating instead of evaluating is a big cost to take. So your version of the template is actually a lot slower than calling toJSon() and using evalution.

  2. Logic belongs to views not templates. Introducing js code (and the need for interpolation) in templates should only be done if necessary.

  3. One could argue that you should be passing model.attributes instead of model.toJSON() avoiding the clone. I guess the reason for not doing so is to avoid allowing the template to change the model's attributes. In addition, you might typically want to augment the result of model.toJSON() with other things, which obviously you don't want to do on the model.attributes

2
votes

A likely reason is because the developers of Backbone.js have allowed you to use any templating engine you desire, and many templating engines work off of simple javascript objects, not Backbone Models.