Collection views in backbone js - Learning Backbone js
This entry is part 9 of 14 in the series for A Complete Guide for Learning Backbone Js
- Introduction and Installation
- Representing your data in javascript
- Defining Models in backbone js
- Adding Validations in models backbone js
- Explaining views in backbone js
- How to use templates in backbone js
- How to improve templates in backbone js
- Collections in backbone js
- Collection views in backbone js
- Template helpers in backbone js
- How to use namespace in backbone js
- How to handle dom events in backbone js and define your custom events (Live Demo)
- Routing in backbone js
Agenda
In the previous lesson, we learned how to use the collection in Backbone js. Now in this topic, we will learn how to generate collection views in Backbone js. Let’s start coding.
What we have till now
So from the previous lesson we have:
// Person Model
var Person = Backbone.Model.extend({
defaults: {
name: 'Guest User',
age: 30,
occupation: 'worker'
}
});
// A List of People
var PeopleCollection = Backbone.Collection.extend({
model: Person
});
// The View for a Person
var PersonView = Backbone.View.extend({
tagName: 'li',
template: _.template( $('#personTemplate').html()),
initialize: function(){
this.render();
},
render: function(){
this.$el.html( this.template(this.model.toJSON()));
}
});
var peopleCollection = new PeopleCollection([
{
name: 'Mohit Jain',
age: 26
},
{
name: 'Taroon Tyagi',
age: 25,
occupation: 'web designer'
},
{
name: 'Rahul Narang',
age: 26,
occupation: 'Java Developer'
}
]);
Three things we need
- Person Model
- Person View
- Person Collection
So we have person model, person view, but the problem is we dont have collection view, a view that collects all smallers view and make it a complete giant view. Lets define one:
Defining a collection
// View for all people
var PeopleView = Backbone.View.extend({
tagName: 'ul'
});
We defined a PeopleView and as we are using li
tag for small view is PersonView that why we defined tagName: ul
in PeopleView. Now we need to define a render method which should be these functionalities.
- Loop over all the person objects
- Should call render for the person objects
- Should display a collection as HTML
Defining render method
So lets just define our render method and implement all of the above functionality one by one.
// View for all people
var PeopleView = Backbone.View.extend({
tagName: 'ul',
render: function(){
// must do certain things as specified above.
//Loop over all the person objects
//Should call render for the person objects
//Should display a collection as HTML
}
});
Let’s create a new object i.e., peopleView and see few things on Chrome developer tools console. I have added initialize function in CollectionView and here is the code for main.js
// Person Model
var Person = Backbone.Model.extend({
defaults: {
name: 'Guest User',
age: 30,
occupation: 'worker'
}
});
// A List of People
var PeopleCollection = Backbone.Collection.extend({
model: Person
});
// View for all people
var PeopleView = Backbone.View.extend({
tagName: 'ul',
initialize: function(){
console.log(this.collection);
},
render: function(){
}
});
// The View for a Person
var PersonView = Backbone.View.extend({
tagName: 'li',
template: _.template( $('#personTemplate').html()),
initialize: function(){
this.render();
},
render: function(){
this.$el.html( this.template(this.model.toJSON()));
}
});
var peopleCollection = new PeopleCollection([
{
name: 'Mohit Jain',
age: 26
},
{
name: 'Taroon Tyagi',
age: 25,
occupation: 'web designer'
},
{
name: 'Rahul Narang',
age: 26,
occupation: 'Java Developer'
}
]);
// on console
// var peopleView = new PeopleView({ collection: peopleCollection });
Here is the result from console:
- So what I can see is three objects in the collection view
- Lots of functions that can be applied to collection views.
So let’s move ahead and use each function and loop over the collection view. Lets for now just run a loop.
// loop over all the person objects in the peopleCollection
render: function(){
this.collection.each(function(person){
console.log(person);
});
}
So first step of looping is done. Now let’s move ahead of the second step i.e., Create a view for each person.
// loop over all the person objects in the peopleCollection
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
console.log(personView.el);
});
}
So far its fine. Now just hold a sec and checkout this carefully. “this” inside the loop lost the reference of the actual collection. Try out these two things to understand it a better way and checkout inline comments.
// loop over all the person objects in the peopleCollection
render: function(){
console.log(this); // reference to collection object.. Pretty useful..
this.collection.each(function(person){
var personView = new PersonView({ model: person });
});
}
//OR
// loop over all the person objects in the peopleCollection
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
console.log(this); // referencing to global window object and its pretty useless..
});
}
So to maintain the reference use this:(checkout inline comments.)
// loop over all the person objects in the peopleCollection
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
console.log(personView.el);
}, this); // at this point we are passing context.. Underscore provides this functionality..
}
So now we have a reference of original collection view inside the loop. So now just lets complete the third task, i.e., rendering the whole collection list.
var PeopleView = Backbone.View.extend({
tagName: 'ul',
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
this.$el.append(personView.el); // adding all the person objects.
}, this);
}
});
// on console
//var peopleView = new PeopleView({ collection: peopleCollection });
//peopleView.render();
//peopleView.el;
Here is console output:
A quick tip: Always return this from your render method to do chaining. For example person.render.el instead of running two commands person.render and then person.el.
So let’s use this tip finish up the lesson. So currently we have: (checkout inline comments.)
// Person Model
var Person = Backbone.Model.extend({
defaults: {
name: 'Guest User',
age: 30,
occupation: 'worker'
}
});
// A List of People
var PeopleCollection = Backbone.Collection.extend({
model: Person
});
// View for all people
var PeopleView = Backbone.View.extend({
tagName: 'ul',
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
this.$el.append(personView.el);
}, this);
}
});
// The View for a Person
var PersonView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#personTemplate').html()),
initialize: function(){
this.render();
},
render: function(){
this.$el.html( this.template(this.model.toJSON()));
}
});
var peopleCollection = new PeopleCollection([
{
name: 'Mohit Jain',
age: 26
},
{
name: 'Taroon Tyagi',
age: 25,
occupation: 'web designer'
},
{
name: 'Rahul Narang',
age: 26,
occupation: 'Java Developer'
}
]);
Let’s do certain things: (checkout inline comments.)
- Remove initialize function from PersonView to use chaining and manually call render.
- Returning this from PersonView render method
- Returning this from CollectionView render
- Adding the whole list on Dom for demo purpose.
// Person Model
var Person = Backbone.Model.extend({
defaults: {
name: 'Guest User',
age: 30,
occupation: 'worker'
}
});
// A List of People
var PeopleCollection = Backbone.Collection.extend({
model: Person
});
// View for all people
var PeopleView = Backbone.View.extend({
tagName: 'ul',
render: function(){
this.collection.each(function(person){
var personView = new PersonView({ model: person });
this.$el.append(personView.render().el); // calling render method manually..
}, this);
return this; // returning this for chaining..
}
});
// The View for a Person
var PersonView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#personTemplate').html()),
////////// initialize function is gone from there. So we need to call render method manually now..
render: function(){
this.$el.html( this.template(this.model.toJSON()));
return this; // returning this from render method..
}
});
var peopleCollection = new PeopleCollection([
{
name: 'Mohit Jain',
age: 26
},
{
name: 'Taroon Tyagi',
age: 25,
occupation: 'web designer'
},
{
name: 'Rahul Narang',
age: 26,
occupation: 'Java Developer'
}
]);
var peopleView = new PeopleView({ collection: peopleCollection });
$(document.body).append(peopleView.render().el); // adding people view in DOM.. Only for demo purpose...
So lets just run this code and see what we have:
Boom.. A complete list of the person displayed on the page. Pretty nice. ;) So now if you are the thing that so far so much code just to see a list. Hold on. This is how we got the whole structure of the application. Now to add Jquery events all we need to call functions and add some new minor features. Trust me once you start checking out jquery events. You will just fell in love with backbone.
Source code
If you are facing any issues. Check out the source code files at github. I will be creating more and more directories in the same repo regarding each post. Still, if you have any doubts you can comment on the blog post itself, and I will try to reply back asap.