Communicating between views in BackboneJS

If you have just started working in BackboneJS then you would have found yourself in a situation where you want one of the views to update or call a function in second view of your application. This is quite common situation while developing a Backbone application. There is no direct way to solve this problem and there may be several workarounds to do this. In this article we will take a look at two of the most common techniques to achieve communication between Backbone views.




Approach 1: Using View Objects

In the first approach we will see the most straight forward technique. In this techniques the first view will create an object of the second view and will call the second view's method directly through that object. Lets see this example:
//View1.js: 
var View2 = require("views/view2");
Backbone.View.extend({

    initialize: function() {
        //create object of the second view to use in current view
        this.view2 = new View2();
    },

    events: {
        "click .my-button": "updateStatus"
    },

    updateStatus: function() {
        //Update the second view using object
        //where updateOtherStatus is defined in view2
        this.view2.updateOtherStatus();
    }
});

//View2.js: 
Backbone.View.extend({

    initialize: function() {
        this.status = 0;
    },

    updateOtherStatus: function() {
        this.status++;
        console.log(status);    //Outputs 1
    }
});

While technically there is nothing wrong with this approach. But think of a situation where view2 has a property that holds some variable of the view and which should be shared throughout the application. Now in above example view1 might have changed that property of the view2. Suppose you application has a third view view3. In view3 you may want to access the most recent value of the view2 property.
See the following snippet:
//View3.js: 
var View2 = require("views/view2");
Backbone.View.extend({

    initialize: function() {
        //create object of the second view to use in current view
        this.view2 = new View2();
        this.view2.showStatus();
    }
});

//View2.js: 
Backbone.View.extend({
    .
    .
    showStatus: function() {
        console.log(status);    //Outputs 0
    }
});

So now you understand the problem. Creating separate view objects to access the views does not maintain the current state of the object globally. In this techniques you will end up creating multiple view objects in you application which will lead to more memory usage. Another disadvantage is that suppose you rename or delete the view2 from your application. In this case all of your application code will break as you have directly referenced view2 throughout your application.

Approach 2: Using Backbone Events

This approach is far more flexible and error proof than the first approach. Here we will harness the power of Backbone events. We will create a global event tunnel in our application and all the communication between the views will take place through this event tunnel.
In your main app.js, write these two lines:
//app.js
App.Notifications = {};
_.extend(App.Notifications, Backbone.Events);

Now rewrite view1 as:
//View1.js
Backbone.View.extend({

    initialize: function() {
        //No object created
    },

    events: {
        "click .my-button": "updateStatus"
    },

    updateStatus: function() {
        //Trigger a custom event which will be captured in view2
        App.Notifications.trigger("updateStatus");
    }
});

Change view2 as:
//View2.js: 
Backbone.View.extend({

    initialize: function() {
        var _self = this;
        _self.status = 0;

        //Catch the event and perform some action
        App.Notifications.on('updateOtherStatus', function (opts) {
            _self.updateOtherStatus();
        }, this);
    },

    updateOtherStatus: function() {
        this.status++;
        console.log(this.status);   //Outputs 1
    }
});

Now check the call from view3
//View3.js: 
Backbone.View.extend({

    initialize: function() {
        //create object of the second view to use in current view
        App.Notifications.trigger("showStatus");
    }
});

Now the output of view2 will be:
//View2.js
Backbone.View.extend({

    initialize: function() {
        var _self = this;
        _self.status = 0;

        //Catch the event and perform some action
        App.Notifications.on('showStatus', function (opts) {
            _self.showStatus();
        }, this);
    },

    showStatus: function() {
        console.log(this.status);   //Now outputs 1
    }
});

As you can notice that view2 now maintains its status and the most recent values are available. This technique is more flexible because even if you rename or delete some of your views, the application will still work and nothing will break.

I hope that was useful. But if you will something is wrong or missed, please feel free to point out in the comments.

We would love to hear from you...

back to top