Home » Backbone » Backbone Views

Backbone Views

Welcome to the Second module of Backbone.js tutorial. In this Module we will cover some basic concepts of backbone Views, how views can be created and instantiated, how we can render the data in html using underscore template. Moving further we will see how to improve the application performance by removing the unused views from DOM and applying events.

These are the topics that we will be covering in this module

  • Creating and Initialization
  • el and $el property
  • setElement
  • render
  • underscore template
  • events
  • remove

 

Views

Backbone Views contain logic to display model’s data instead of containing HTML markup or css styling. Backbone views play the controller’s role also as they are responsible to handle user events and also to update the User Interface (DOM) when model data changes.

So basically, Views depend on model’s data. Model trigger events that the view can handle, and update the User Interface (if needed). Views can also handle the events raised by DOM or by user and manipulate the model’s data accordingly.

 

Creating and Initialization
Creating a new View is same as creating a model. New View can be created by using Backbone.View.extend();

Let’s start with creating a simple backbone view

var view = Backbone.View.extend({ // extending Backbone.View to create your own view
                   tagName:'h1', // tagName will create DOM element (h1 in this case) for this view
                   className:'center-align', // className will apply class for this view
                   attributes:{ // attributes will attach the attribute for this View, You can create as many attributes as you want seperated by comma (see the DOM element in result)
                        'data-attribute':'attribute-value'
                   },
                   initialize:function(){ // this method will be called as soon as View is loaded or instantiated
                      this.$el.html("This is Heading"); //setting html for h1
                  }
             });

var newView = new view();

// appending h1 in body tag
$('body').append(newView.el);

css-style:

.center-align{
  background-color: grey;
  color: black;
  text-align:center;
}

RESULT:
Above code will create DOM element

<h1 data-attribute="attribute-value" class="center-align">This is Heading</h1>

Above code will create a DOM element within view itself and append that in body. There is another way of creating view in backbone, which needs HTML file to render the model’s data. Below is the code to do that, this code will create DOM element by using HTML file and set the data for that element in view.js.

HTML:

<div id="id_subHeading">Sub heading</div>

view.js

var subView = Backbone.View.extend({
                 tagName:'h1', // creating tagName just to show behavior in this case
                 attributes:{
                    'data-attribute':'attribute-value'
                  }
               });
var subHeading = new subView({el:'#id_subHeading'}); // setting #id_subHeading as a DOM element for this view.
subHeading.$el.css({'background-color':'blue'}); // applying style on DOM element

DOM element:

<div id="id_subHeading" style="background-color: blue;">Sub heading</div>

In this example DOM elemenet for “subView” is #id_subheading.
The important point to note here is, you defined tagName for subView(h1) but the resulted DOM element is <div> instead of <h1> , it is because the tagName property will have no affect if the DOM element is already defined in HTML.
If you want to pass data from View.js you should use this.$el.html(“This is Heading”) as explained in previous example.

You must have noticed that at sometimes I am using el and sometimes $el. So before going further let’s take a look at el and $el.

 

el and $el property

el is the most important property of Backbone’s view which basically refers to DOM element. According to backbone documentation, each view should have one el which is used to render view content in it.

There are two ways to define el for a backbone view (as explained above). Either you can have el within the view itself by using tagName (firstExample), or you can set el by using css selectors(Second example). The important point to note here is; if in first approach you do not define the “tagName” property then by default view will render as <div> element.

$el is used to invoke Jquery function on Backbone view; as we did in second example which invokes .css() function to set the background color of subView

 

setElement

If you’d like to apply a Backbone view to a different DOM element, use setElement() method, which will also create the cached $el reference and move the view’s delegated events from the old element to the new one. (from Backbone documentation)

So, Basically setElement replaces the attached DOM element.

var Div1 = $('&lt;div&gt;Main Div1&lt;/div&gt;');
var Div2 = $('&lt;div&gt;Replaced Div2&lt;/div&gt;');

var View = Backbone.View.extend({

});

var newView = new View({el: Div1}); // here Div1 is the DOM element for this view

newView.setElement(Div2); // replacing the view's el.
$('body').append(newView.el);

<span style="font-size: medium; font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; line-height: 19px;">DOM Element</span>
<div>Replaced Div2</div>

 

render

Backbone views provide optional render() method which can be used in cases where you want to render your view using third party template libraries. You can also pass the model data or data object to render() method, you will learn later in this module about how can you display this data in your html using underscore templates. By convention render() method should always return “this” because it makes the view reusable.

HTML:

<p id="id_userName">Display User Name</p>

view.js

// Create new view
var view = Backbone.View.extend({
                  initialize:function(){
                  // In initialize you can check if the model changes, then re-render the view to keep the view in sync with model data.
                    this.model.on('change',function(){
                    this.render(); // if model changes, re-render the view.
                  },this);
},
                  // render function, to render the view 
                  render:function(){
                     this.$el.html(this.model.get('name')); // get "name" attribute data from model and set it as element's html
                     return this;
                   }
                });

// Create new model
var modelPerson = Backbone.Model.extend({});

var mModelPerson = new modelPerson({
              name:'Himanshu'
});

Now you should pass mModelPerson as my view’s model and #id_userName as view’s el.

var mainView = new view({model:mModelPerson, el:'#id_userName'});
mainView.render();

Below code will change the value of model’s “name” attribute after 3000ms , which will trigger model’s change event and will call the view’s render() function again.

_.delay(function(){
     mModelPerson.set('name','Himanshu Chahar');
},3000);

Another way of inserting data in DOM element is using templates.

There are lots of templates available but I will only cover underscore template.

 

underscore template

Backbone itself doesn’t provide any template to render the HTML but underscore’s templates can be used to render the view (To read about underscore template click here). Let’s take a look:

There are two ways to display data in HTML using underscore template.

1st way:

var view = Backbone.View.extend({
             initialize:function(){
             },
             modelData:null,
             events:{
             },
             render:function(){
               // JSON object, or you can pass model also.
               var personDetails = {name:"Himanshu", age:26, country:"India"}

               // _.template method will render the html. First Parameter is the HTML markup and second is the JSON object.
               //Variable name like name, age, country should be same as model's attributes.
               this.$el.html(_.template('Name: <%= name%> </br> Age: <%= age%> </br> Country: <%= country%>', personDetails));
               return this;
             }
        });

var mainView = new view({el:'body'});
mainView.render();

 

2nd way:

HTML:

<script type="text/html" id="id_renderDetails">
  <div>Name: <%=name%></div>
  <div>Age: <%=age%></div>
  <div>Country: <%=country%></div>
  <div>Hobbies:</div>
  <% _.each(hobbies,function(e){ %>
      <li> <%= e %></li>
  <%});%></div>
</script>

view.js

var view = Backbone.View.extend({
              initialize:function(){
              },
              modelData:null,
              events:{
              },
              render:function(){
                // id of script tag.
                var renderDetails = $('#id_renderDetails').html();
                var personDetails = {name:"Himanshu", age:26, country:"India",hobbies:["Football", "Photography","Console Games"]}
                this.$el.html(_.template(renderDetails, personDetails));
                return this;
              }
           });

var mainView = new view({el:'body'});
mainView.render();

Both the approach are almost same, the only difference is second approach uses script tag in which you have <div>’s and <li>’s to populate the data from model.

I myself generally prefer second approach because it allows to maintain the cleaner code.

 

events

Same as models, Backbone views can also have events, but they only handle those events that occur in their own elements.
Syntax ‘eventName css-selector’: ‘callBackFunction’, eventName can be any of the DOM event.

View = Backbone.View.extend({
            initialize:function(){
            // fetching the date attribute's value from model and assigning it to modelData variable
              this.modelData = this.model.get('date');
            },
            modelData:null, // variable to hold date
            events:{
            // Binding click event
              'click #id_updateDate':'displayYear'
            },
            displayYear:function(){
               // this function will update the html with current date
               $('#id_displayDate').html(Date());
            },
            render:function(){
               var html = "<div id='id_displayDate'>"+this.modelData+"</div>"+
               "<button id='id_updateDate'>Update Date</button>"
                this.$el.html(html);
                return this;
             }
        });

var dateModel = Backbone.Model.extend({});

var mDateModel = new dateModel({
         date:Date()
});

var dateView = new View({model:mDateModel, el:'body'});
dateView.render();

DOM element:

<div id="id_displayDate">current time</div>
<button id="id_updateDate">Update Date</button>

Above code has a button “Update Date”; which has its click event in events property of view.

You can only attach click event of those element which are present in current view, i.e. if you have a button in other view then you cannot have click event for that button in this view.

 

remove

Now days there are applications which have more number of screens, in such applications  it is very important to remove unused resources or else it will result in memory leaks. Memory leaks may result in poor performance or may sometimes results in application crash also,which will be very frustrating for user.  To overcome this issue backbone provides Remove() function which can be used to remove unused view from DOM and undelegate all the events of that view. In good practice, you should call remove() method on those views which are not in use or which are not being currently displayed to the user, this practice helps to keep the DOM lightweight and prevent memory leaks.

HTML:

<p id="id_userName">Display user Name</p>

view.js

var view = Backbone.View.extend({
                  initialize:function(){
                  },
                  render:function(){
                     this.$el.html(this.model.get('name'));
                     return this;
                  }
               });

var modelPerson = Backbone.Model.extend({});

var mModelPerson = new modelPerson({
         name:'Himanshu'
});

var mainView = new view({model:mModelPerson, el:'#id_userName'});
mainView.render();

// this will remove the view from DOM
mainView.remove();

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>