In the previous post we learned about Model Binding in isolation. There are many places where model binding can provide benefit. Where we see model binding the most is in relation to using views. Usually we want the view to depict those changes in the model. In this post we will bind a model to a view.
In the following example the view will be updated when the model changes.
<html > <head> <title></title> <script src="/scripts/jquery-1.8.3.js" type="text/javascript"></script> <script src="/scripts/underscore.js" type="text/javascript"></script> <script src="/scripts/backbone.js" type="text/javascript"></script> </head> <body> <div id="container-movie"></div> <script type="text/template" id="template-movie"> Title: <%=title%>; Rating: <%=mpaaRating%> </script> <script type="text/javascript"> var Movie = Backbone.Model.extend({}); var MovieView = Backbone.View.extend({ el: "#container-movie", template: _.template($("#template-movie").html()), initialize: function() { this.model.on("change", this.render); }, render: function() { console.log("MovieView render; Movie Title: " + this.model.get("title")); var htmlOutput = this.template(this.model.toJSON()); this.$el.html(htmlOutput); return this; } }) var movie = new Movie({ title: "The Lion King", mpaaRating: "R" }); var movieView = new MovieView({ model: movie }); movie.set({ title: "Titanic" }); movie.set({ title: "The Godfather" }); </script> </body> </html>
In the MovieView initialize function, we bind the view’s render function to the model. The first parameter “change” identifies the event we should bind to. The second argument identifies the function to call when the event is triggered. So in this situation, anytime a change happens to the model, then trigger the render function. Let’s ignore the argument “this” for the time being. I will go over the argument “this” in the following example.
*****************************************************************
In following example, we will describe the use of the argument “this” when binding model to the view. I want to keep it fairly simple so I removed the code that manipulated the DOM.
<script type="text/javascript"> var Movie = Backbone.Model.extend({ type: "Movie" }); var MovieView = Backbone.View.extend({ el: "#container-movie", template: _.template($("#template-movie").html()), type: "MovieView", initialize: function() { this.model.on("change", this.render, this); this.model.on("change", this.render); }, render: function() { console.log(this.type); return this; } }) var movie = new Movie({ title: "The Lion King", mpaaRating: "R" }); var movieView = new MovieView({ model: movie }); movie.set({ title: "The Godfather" }); </script>
In both the Movie model and MovieView view I added a property called “type”. The “type” property is hard coded to the kind of object that is created.
In the view’s initialize function we bind the model to the view twice on the change event. When the model is updated, the render function will be called twice. The first statement passes in the argument “this” and the second statement does not have a 3rd argument.
Since we are in the context of the movieView object when we declare the first binding, the argument “this” will reference the movieView object. When the model change event is triggered, the render function will be called and in the render function “this” will reference the movieView object.
In the second binding, “this” is not identified. When the model change event is triggered and the render function is called, the movie object is assigned to “this”. Since the movie object triggered the event, “this” is assigned the movie object”.
I hope this post clarified binding and the use of “this”.
Awesome explanation of binding model change events to views
I like your tutorial; but I am having an issue with it.
I can not reproduce your results. In fact I am getting an error when I render the page.
I see the following message when I look in the console within chrome.
Uncaught TypeError: Cannot call method ‘html’ of undefined
Backbone.View.extend.render
triggerEvents
Backbone.Events.trigger
_.extend.set
(anonymous function)
A little correction (probably because an update of backbone library):
Trying to execute the first example of this post, i was having a problem, firebug was telling me that “this.model is undefined”. when i was setting another title for my movie instance.
Using
console.log(this instanceof Backbone.View)
was returning false, and
console.log(this instanceof Backbone.Model)
was returning true
I’ve realized that maybe is because in Backbone.View.initialize() code, you use the following command:
this.model.on(“change”, this.render);
and, since the event that triggers the call to this.render() is a Backbone.Model event, and not a Backbone.View, “this” inside the render() function was having a reference to the Model instead of the View. I’ve replaced “this.model.on(…)” with:
“this.listenTo(this.model, “change”, this.render);”
and now it’s working.
Great series of tutorials about backbone, by the way. I was bored of reading books about the topic without fully getting how the different component has to be linked between, until i’ve found yours!!
this line # 23 in the first one needs to be changed to
“this.model.on(“change”, this.render, this);”
instead of
“this.model.on(“change”, this.render);”
This has been causing errors since you are not passing the “this” parameter on the change event.