Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide Backbone Model/Collection as first parameter to jQuery Deferred callbacks #1774

Closed
pmaccart opened this issue Oct 26, 2012 · 4 comments

Comments

@pmaccart
Copy link

Hi all,

We've been leveraging the Deferred objects returned from Backbone.sync calls extensively in our application, and have found those to be very convenient, particularly when views depend on multiple models.

One case we've struggled with is when we have nested Backbone views, we're forced to provide both the collection instance and deferred object to the child view constructor:

var View1 = Backbone.View.extend({
    render:function () {
        var collection = new Backbone.Collection();
        collection.url = '/path/to/resources';

        var deferred = collection.fetch();
        var subview1 = new Subview1({collection:collection, deferred:deferred}).render();
        this.$el.append(subview1.el);

        deferred.done(this.onCollectionFetched);

        return this;
    },

    onCollectionFetched:function (collection) {
        // do stuff with collection
    }
});

var Subview1 = Backbone.View.extend({
    initialize:function () {
       this.collection = this.options.collection;
       this.deferred = this.options.deferred;
    },

    render:function () {
        this.deferred.done(this.onCollectionFetched);
        return this;
    },

    onCollectionFetched:function (collection) {
        // do stuff with collection
    }
});

The example above is fairly trivial, but quickly becomes complex has the hierarchy grows (particularly if certain views in the hierarchy should not be blocked from rendering based on data not being ready). It would be nice if the deferred would be modified slightly such that the collection (or model) was provided as the first argument to the callbacks:

var View1 = Backbone.View.extend({
    render:function () {
        var collection = new Backbone.Collection();
        collection.url = '/path/to/resources';

        var deferred = collection.fetch();
        var subview1 = new Subview1({deferred:deferred});

        deferred.done(this.onCollectionFetched);

        return this;
    },

    onCollectionFetched:function (collection) {
        // do stuff with collection
    }
});

var Subview1 = Backbone.View.extend({
    initialize:function () {
       this.collection = this.options.collection;
       this.deferred = this.options.deferred;
    },

    render:function () {
        this.deferred.done(this.onCollectionFetched);
        return this;
    },

    onCollectionFetched:function (collection) {
        // do stuff with collection
    }
});

I've attached a pull request to this issue illustrating a potential fix, but am certainly open to suggestions and other approaches to take.

Thanks,
Phil

@braddunbar
Copy link
Collaborator

Hi @pmaccart! Is there any reason you can't use the reset or sync event on the collection to trigger your callback?

@pmaccart
Copy link
Author

We started off using those, but at the scale our our application (upwards of 10 layers of nested Backbone views in most cases), it became very unwieldy to supply the models/collections all the way down through the views, as well as keeping track of what particular models/collections had been fetched. We've been experimenting with the deferred pattern and have found it much more pleasant to code against, particularly in cases where a single view requires multiple models:

var View = Backbone.View.extend({
  render:function () {
    var peopleCollection = new PeopleCollection(),
         tagsCollection = new TagsCollection();
   $.when(peopleCollection.fetch(), tagsCollection.fetch())
       .then($.proxy(this.render, this));
 }
);

This pattern works great when a single view is managing the collections, but when lots of nested views rely in different combinations of the data to render, things break down. It'd be much cleaner to be able to provide the deferred for a fetch, then trust the collection/model the fetch was invoked upon would be provided to the callbacks.

Will have a pull request in shortly...

@pmaccart
Copy link
Author

Closing this; pull request created issue #1775. I'm still working on polishing my GitHub skills...

@tomalec
Copy link

tomalec commented Jun 9, 2013

If all you need is just model in fulfillment handler of your promise you can take a look on my single-line plugin ;)
https://github.com/tomalec/Backbone.promissedSync
but note that, due to #2345, for save you will still need to use either $.when( model.save() ) or Q( model.save() )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants