Tuesday, February 4, 2014

Backbone.js - Getting Started Tutorial

When I started learning backbone.js, though there were several getting started tutorials, all of them seemed a little aggressive, since they introduced all the backbone features in a single, supposedly simple application. In this tutorial I am going to introduce each of backbone basic concepts incrementally and kind of provide a less steeper introduction to backbone.js for beginners.

Lets jump right in....

We will start out with a bare bones html file, which can be thought off, as the anchor or home page for the backbone application. Lets name it bb-intro.html.

Initial listing of bb-intro.html




Next we will create a "router" in backbone, it is like a navigator component, which maps URLs to views/templates.

Lets have 3 pages(views) in our application, to be able to display these on demand we will define the following routes.


 var AppRouter = Backbone.Router.extend({
   routes : {
    "" : "showPage1",
    "page1" : "showPage1",
    "page2" : "showPage2",
    "page3" : "showPage3"
   },
   showPage1 : function() {
    new AppViewPage1().render();
   },
   showPage2 : function() {
    new AppViewPage2().render();
   },
   showPage3 : function() {
    new AppViewPage3().render();
   }
});

  
var appRouter = new AppRouter();
Backbone.history.start();


The route entry "" implies the default html page and refers to the following URL
http://<host-name>:<port number>/<web-context>/<path-to-html>/bb-intro.html
or
http://<host-name>:<port number>/<web-context>/<path-to-html>/bb-intro.html#


The entry "page1" refers to the following URL:
http://<host-name>:<port number>/<web-context>/<path-to-html>/bb-intro.html#page1

The entry "page2" refers to the following URL:
http://<host-name>:<port number>/<web-context>/<path-to-html>/bb-intro.html#page2

and so on....I think you get the picture here :)


Next up, is the views like AppViewPage1, AppViewPage2, AppViewPage3, these are as you might have guessed javascript objects defined as follows:



 var AppViewPage1 = Backbone.View.extend({
  template : _.template($('#page1').html()),
  render : function() {
   $('#container').html(this.template());
  }
 });
  
  
 var AppViewPage2 = Backbone.View.extend({
  template : _.template($('#page2').html()),
  render : function() {
   $('#container').html(this.template());
  }
 });
  
 var AppViewPage3 = Backbone.View.extend({
  template : _.template($('#page3').html()),
  render : function() {
          $('#container').html(this.template());
  }
 });


The code for each AppViewPage is quite simple stereotypical, for illustration purposes.
We use the underscore library's api _.template( ) to load a template string
And in the view's render method, we simply assign html content of the div with id "container" using familiar jQuery syntax.

Next up is the definitions of the template themselves. These are html templates containing valid html elements.





Thats it! When you access the above html in browser, it should show the following screens with proper navigation when clicked on the hyperlinks.

Notice that the hrefs in the templates, refer to relative URLs, with values like "#page1", "#page2" and "#page3". This is same as the values we specified in the mapping in our router definition.







Now that we are comfortable with navigating between views, using backbone. Lets turn our attention to features called model and collection provided by backbone.

Lets jump right in by defining a model and collection and try to use the same in our view.


 MyModel = Backbone.Model.extend({
  defaults : {
   title : 'Default Title',
   status : 'Initiated at '+new Date(),
   attrib1 : 'Value1',
   attrib2 : 'Value2',
   attrib3 : 'Value3'
  }
});

 MyCollection = Backbone.Collection.extend({
  model : MyModel,
 });
 
 var myCollection = new MyCollection();
 myCollection.add(new MyModel({title:'Page1'}));
 myCollection.add(new MyModel({title:'Page2'}));
 myCollection.add(new MyModel({title:'Page3'}));
 myCollection.add(new MyModel());

The above code defines a MyModel and MyCollection. We then instantiate a MyCollection object and add 4 MyModel objects with custom titles.

When the template is attached to the view, we need to additionally pass the collection as a template parameter. This can be done as shown in the code below:
  
var AppViewPage1 = Backbone.View.extend({
template : _.template($('#page1').html()),
   render : function() {
 $('#container').html(this.template({mydata:myCollection.toJSON()}));
   }
});



The template itself needs to be tweaked to iterate over the collection and start displaying the passed data parameters. This can be easily done as seen in the snippet below:


Apart from above mentioned features, the backbone model does provide the following important features:

Ability to listen to changes in model
In the model's initialize function, we can listen for changes to specific model attributes as follows:
initialize: function(){
            this.on("change:myattrib1", function(model){
                var newvalue = model.get("myattrib1");
                alert("Changed myattrib to " + newvalue );
            });
}


Interact transparently with a REST service back end
On the model we can invoke stock framework methods like save( ), destroy( ) and fetch( ), which result in HTTP methods PUT, POST, DELETE and GET, getting fired under the hood by the framework against a URL specified in the model's attribute called 'urlRoot'.

Thus there is no need to explicitly use jquery or ajax to make server side requests, the backbone.js model does it for you transparently.

    var UserModel = Backbone.Model.extend({
        urlRoot: '/user',
        defaults: {
            name: '',
            email: ''
        }
    });

    var user = new Usermodel();
    // Notice that we haven't set an `id`
    var userDetails = {
        name: 'Ganesh Ghag',
        email: 'ganeshghag@gmail.com'
    };

    // Because we have not set a `id` the server will call
    // issue a post  /user with a payload of userDetails data above
    // The server should save the data and return a response containing the new 'id'
    user.save(userDetails, {
        success: function (user) {
            alert(user.toJSON());
        }
   })



Support for Model data validation
There is a provision in the backbone model to provide standard callback to validate model data before submission to server and also to raise error( ) callback in case validation fails. This is depicted below:


// If you return a string from the validate function,
// Backbone will throw an error
validate: function( attributes ){
            if( attributes.age < 0 ){
                return "Negative values are not allowed";
            }
},
initialize: function(){
            this.bind("error", function(model, error){
                alert( error );
            });
}

So far we have been able to use backbone to display views, navigate between views and bind and show model data and collections, into the views.

Lastly to attach events to elements in our backbone views is as easy as specifying events attribute of Backbone.View as follows:


SearchView = Backbone.View.extend({

        events: {
            "click input[type=button]": "doBtnClick"
        },
        doBtnClick: function( event ){
            alert( "from inside search button click" );
        }
}

});


With this we have covered most basics about the the backbone framework. You should now be heading towards more advanced tutorials on backbone.

Cheers!

3 comments:

Sanket said...

Excellent writeup. Single page mobile web application can be easily made with deadly combination of Phonegap and Backbone.js

Unknown said...

Codeureka.com provides high level view of Android Tutorial for Beginners library to build client-side application, how backbone models and collections can be used to develop and application how views can be used to render the data using underscore templates.

for ict 99 said...

It is very useful article on Backbone.js which is very helpful for the single page web application developers like me.

Backbone.js Training | Backbone.JS Training in Chennai