Monday, April 01, 2013

Making your Backbone objects into promises

So awesome.

I used to return back promises from my views, for example.  Now I just make my entire view implement the Promise API.  In this fashion, whomever creates the view can wait for a result (think modal popup with the possibility of multiple pages of user data being returned back to the base page).


    var MyChildView = Backbone.View.extend({
       dfd: null,

       initialize: function () {
           this.dfd = $.Deferred();
           this.dfd.promise(this); // Make the view a promise

           this.dfd.always(this.remove); // Self cleanup anyone?
       }

       //Later
       method: function () {
           this.dfd.resolve({ foo: 'bar' });
       }
    });

This enables now something like the following.
    var MyParentView = Backbone.View.extend({
       render: function () {
           var childview = new MyChildView();
           childView.then(this.doSomethingElse); // Do something meaningful with the promise
       }
    });
This approach is clearly superior than events or success callbacks when your parent is waiting on the result of its child. It also allows your views to become parent of entire asynchronous workflows orchestrated with promises.

2 comments:

svlada said...

Hi Adam,

I have read your 9 Tips for a clean BackboneJS App, kudos for really great presentation.

I am building structure for my next project and I am wondering what do you think of following:

1. View will be used just to render templates. Views are injected into the "Controller"

2. Code for View events is kept outside of view. Something like:

SampleView.on('button.click', function() { ... do stuff here ... });

3. Also Controller is calling render() on View each time some service call is resolved. For example

Note: Below is just pseudo-code

Service.getSampleData = function() {
this.dfd = $.Deferred();
... invoke ajax service ...
if (success) this.dfd.resolve(ajax data) else this.dfd.reject;
return this.dfd.promise();
}

and then render SampleView

when(Service.getSampleData()).then( SampleView.render())

Please share your taught's with me.

svlada said...

On additional thing, it is probably better to do something like this:

View.getModel().setData({ ... JSON returned from service ...})

instead of calling explicitly View.render()