Add Me!Close Menu Navigation

Blog and Lab for developers

Add Me!Open Categories Menu

Backbone.js Tutorial – VI. Synchronization and persistence

Introduction

And finally we come to the last topic of the tutorial on Backbone.js, which will work to see the mechanisms of persistence and synchronization with the server that offers the library. In models we saw how we could create, modify and delete models in our application, but never said how we could send that information to the server to store or process it.

As we discuss in this topic, Backbone defines a default behavior that will help us keep the data synchronized between the client and server.

Synchronizing with the server models

When you synchronize a model Backbone uses internally Backbone.sync() function which by default make an Ajax call to server method relying on the $.ajax() jQuery or Zepto.js. That call RESTful Ajax is an application in which Backbone serialize all attributes of the model in a JSON string to send. If everything is correct, the server returns another string JSON with those attributes that have been modified from the server, and Backbone proceed to update the model on the client to be synchronized with the server status.

For Backbone can perform this process, you need to know the URL of the collection associated with the model, since the default behavior of the library is mapped CRUD operations (create, read, update, delete) to the following addresses REST:

create → POST /collection
read → GET /collection[/id]
update → PUT /collection/id
delete → DELETE /collection/id

That is, the first thing to do is attach to model the base URL of the collection (the ‘/collection‘ from the list above) on which to perform these operations. This URL expected from the url property of the model, which can be a string or a function. If you do not specify anything in the property, the default implementation will collect the base URL of the collection belonging to the model.

Users = Backbone.Collection.Extend ({
     url: '/users/'
 });
var users = new Users();
User = Backbone.Model.Extend();
var user = new User({'name': 'John Doyle'});
users.add(user);

Both the creation of the model and its modification by the method set() does not imply the Backbone.sync() call, so if you want to synchronize our model after these operations have to use the method save([attributes], [options]) of the model. This function is similar to the method set() and will update those attributes that are passed as first parameter, but also invoke Backbone.sync() to synchronize with the server. Also we use the second parameter save() to specify the call options $.ajax() that takes place inside:

user.save({}, {              // generate POST /users - content: {name: 'John'}
     success: function() {
         alert ("User saved successfully");
     }
 }); 

In this example the operation save() generates a POST because it is a creation operation (‘create’). Backbone performs an operation that is created whenever we try to synchronize a model instance that does not contain any value in its ID attribute, which defaults to the id attribute or that we have designated as an identifier through idAttribute attribute when defining the model.

If the server returns a JSON object it will be used to update the model. This is typical to happen precisely in the operations building, where the server will return the identifier of the new element created.

user.save({}, {              // generate POST /users - content: {name: 'John'}
     success: function() {
        // Assuming that the server returned the object {"id": 1}
        alert(user.id);  // show 1
     }
 }); 

In this example we have assumed that the server returns a JSON object with the identifier assigned to the new instance synchronized, so that object Backbone applied on the model instance.

Once the model you have your ID, any subsequent operation on the model instance will cause a refresh operation (‘update’) on the server:

user.save({surname: ‘Doyle’}); // is generated PUT /users/1 – content {id: 1, name: ‘Jonh’, surname: ‘Doyle’}

As the example, the update operation sends the entire contents of the object to the server via a PUT to the specific URL of the model.

Apart from the save() method there are two other methods that perform synchronization model to the server: fetch([options]) and destroy([options]). The fetch() method performs a read operation (‘read’) and serves to refresh the data model from the existing copy on the server:

var user = new User({id: 1})                    //Create an instance initializing the object ID you want to recover
users.add (user)                                //Add the instance to the collection to know the url based backbone of the collection
user.fetch ({                                   // generate GET /users/1
     success: function () {
          alert(JSON.stringfy(user.attributes)) // {print “id”: 1, “name”: “John”, “surname”: “Doyle”}
    }
}); 

On the other hand serves to generate an erase operation (‘delete’) and delete the server object instance:

var user = new User({id:1});      // Create an instance initializing the object ID that users want to 
users.add(user);            // Add the instance to the collection for 
user.destroy();                // is generated DELETE /users/1 

As was the case with save() functions both as a parameter to define the options to be used in Ajax.

As we have seen in all these examples, we have always introduced the model instance we wanted to synchronize within a collection, as a mechanism for Backbone could retrieve the base URL of the collection and thus form the REST operations for each CRUD operation. If for any reason we want to work with model instances without having to associate them with any collection, we can use the attribute UrlRoot in defining the model, where we define precisely the base path:

User = Backbone.Model.Extend ({
     UrlRoot: '/users/'
});
var user = new User({id: 1});
user.fetch();                  // generates GET /users/1 

As we see, defining UrlRoot need not be associated with any collection a model to synchronize with the server, you getting exactly the same behavior as if it were.

Finally, if we want a particular model does not have this behavior by default and we associate it with a final URL for all operations of the model, we can define directly the url property in the definition of the model:

User = new Backbone.Model.Extend ({
     url: '/user';
 });
var user = new User({id: 1});
user.fetch ({                                // generates GET /user
     success: function () {
         user.save ({'name': 'John'}, {      // generate PUT /user
             success: function() {
                 user.destroy()              // generates DELETE /user
             }
         });
     }
}); 

This backbone will always perform CRUD operations on the same URL fixed, without adding or removing id, whether or not within a collection, and whether or not it has any value defined in UrlRoot.

Collections and Synchronization

As discussed in the previous section the concept of synchronization of models is closely linked to the concept of collection due to the nature of REST interfaces. In the examples we have seen that setting the base URL of the collection the models incorporated in it will be able to perform the synchronization operations.

Apart from the existing synchronization methods in the models, the collections have a method to retrieve an entire collection from the server: the method fetch([options]):

User = Backbone.Collection.extend({
    url: '/users'
});
var users = new Users();
users.fetch({                      // generates GET /users 
    success: function(){
        alert('Recovered ' + users.length + ' users');
    }
});

This method performs a GET operation on the base URL of the collection, and expects a JSON object consisting of an array of instances of models to be included in the collection. This operation will refresh the backbone event.

Customizing synchronization

As mentioned at the beginning, each synchronization operation actually performs the function Backbone.sync(), whose default implementation synchronizes the data with the server via Ajax calls. If we wish, we can replace this function and switch to another synchronization strategy, such as using one of the HTML5 features as WebSockets or Local Storage. For example, we can override this feature to simply show the console operations to be performed:

Backbone.sync = function (method, model, options) {
     console.log (method, model, options);
     options.success (model);
 };

As shown in the example, the function Backbone.sync() expects 3 parameters:

  • method: CRUD method to be performed (‘create’, ‘read’, ‘update’, or ‘delete’)
  • model: The model to save (or collection to be read)
  • options: The settings of the application, which will include callbacks success and failure

All I expected Backbone is invoking the callback functions options.success() or options.error() in appropriate cases.

Overwrite function Backbone.sync() allow us to change strategy on a global synchronization, but it is also possible to override this function only in a particular model or collection:

Users.prototype.sync = function (method, model, options) {/ * ...  * /} 

A good example of customization Backbone.sync() is the Local Storage Adapter . Be sure to check it out.

Conclusion

With this topic I finished the tutorial by Backbone. As said earlier attempt to make a sample application, although there is enough material in the tutorials section of backbone.

This tutorial will try to keep updated with the new features that will be incorporated into subsequent versions of the library.

Posted By Fran Alvarez

12 Responses to “Backbone.js Tutorial – VI. Synchronization and persistence”

  1. Thanks for any other wonderful post. Where else may anyone get that kind of info in such an ideal approach of writing? I have a presentation subsequent week, and I’m on the search for such information.

  2. Channi says:

    Brilliant piece of work. You write quite well.
    Code is wrong in many snippets, some typos, can be amended easily.

    • Thanks for your comment, Channi.

      I am very grateful and I will try to improve the code slowly for the new entries.

      • TYPOS:

        Code Block 1, Line 4:
        IS: var users = new User();
        SHOULD BE: var users = new Users();

        Code Block 4, Line 1:
        IS: user.save({apellidos: ‘Doyle’}); // is generated PUT /users/1 – content {id: 1, name: ‘Jonh’, name: ‘Doyle’}
        SHOULD BE: user.save({surname: ‘Doyle’}); // is generated PUT /users/1 – content {id: 1, name: ‘Jonh’, surname: ‘Doyle’}

        Code Block 5, Line 5:
        IS: alert(JSON.stringfy(usser.attributes)) // {print “id”: 1, “name”: “John”, “surname”: “Doyle”}
        SHOULD BE: alert(JSON.stringfy(user.attributes)) // {print “id”: 1, “name”: “John”, “surname”: “Doyle”}

        Code Block 9, Line 1-3:
        IS: User = Backbone.Collection.extend({ url: ‘/user’ });
        SHOULD BE: Users = Backbone.Collection.extend({ url: ‘/users’ });

        Code Block 10, Line 1:
        IS: Backbone.Sync = function (method, model, options) {
        SHOULD BE: Backbone.sync = function (method, model, options) {

  3. Ravi says:

    Hi Fran

    Can you please throw light on ‘url’

    Which server link needed to be specified.

    thanks
    ravi

  4. Thank you, Fran. This is one of the most helpful Backbone tutorials I have found – properly coding your Collections and Models for RESTful/CRUD.

    I’ll be sharing this with anyone seeking to learn a proper implementation of Backbone.

  5. Praveen says:

    wonderful post. I am facing issue with overriding the sync method so I can add request headers to all ajax call going through models. Any help will be greatly appreciated .

  6. Dev Addiction – Lab» Blog Archive
    » Backbone.js Tutorial & Great stuff

  7. I will right away grasp your rss feed as I can’t to find your email subscription link or newsletter service. Do you’ve any? Please let me know so that I could subscribe. Thanks.

Leave a Reply