开发者

Is it possible to initialise a backbone Collection with object IDs rather than objects?

I have a Backbone.js Collection and I have an array of model IDs that I want to populate it. I know that I could fetch these objects one by one, build an array of objects and pass them into the Collection's constructor as an array.

What I'd like to开发者_高级运维 be able to do is pass the array of object ids into the constructor as initial data, and get the Collection to fetch them, possibly as batch, as per this.

Doable?


When you call 'fetch' on a Backbone.Collection, it in turn calls Backbone.sync, which by default just asks the collection for the url to use.

So if your server responds to:

/models/batch/?ids=1,2,3,4

You could do something like:

var MyCollection = Backbone.Collection.extend({

    model: Model,

    url: '/models',

    initialize: function(models, options) {
        ids = options.ids || [];
        if (ids.length > 0) { 
            this.fetchByIds(ids);
        }
    },

    fetchByIds: function(ids) {
        // Save a reference to the existing url
        var baseUrl = this.url;

        // Assign our batch url to the 'url' property and call the server
        this.url += '/?ids=' + ids.join(',');
        this.fetch();

        // Restore the 'url' property
        this.url = baseUrl;
    }
});

And use it like so:

var coll = new MyCollection({}, {ids: [1, 2, 3, 4]});

You'd have to pass the ids in the options parameter, because the Backbone.Collection constructor function sets the models passed in the first parameter before it calls the 'initialize' function.

Theoretically, this should work (read: completely untried).


On initial page load, you shouldn't use fetch -- it should be bootstrapped as using reset described here: http://documentcloud.github.com/backbone/#FAQ-bootstrap.

From the link:

Loading Bootstrapped Models

When your app first loads, it's common to have a set of initial models that you know you're going to need, in order to render the page. Instead of firing an extra AJAX request to fetch them, a nicer pattern is to have their data already bootstrapped into the page. You can then use reset to populate your collections with the initial data. At DocumentCloud, in the ERB template for the workspace, we do something along these lines:

<script>
  Accounts.reset(<%= @accounts.to_json %>);
  Projects.reset(<%= @projects.to_json(:collaborators => true) %>);
</script>


You can actually set url to a function too. I'd just override fetch instead of fetchByIds: Also, I think that baseUrl is for the Model only, not the Collection. I think rulfzid has the right idea, but I think I'd do it like so:

var MyCollection = Backbone.Collection.extend({
  model: Model,

  initialize: function(models, opts) {
    if (options.ids) {
      this.fetch(options.ids);
    }  
  },

  url: function() {
    var url = '';
    if (this.fetch_ids) {
      // pass ids as you would a multi-select so the server will parse them into
      // a list for you.  if it's rails you'd do: id[]=
      url = '/models?id=' + ids.join('&id=');
      // clear out send_ids
      this.fetch_ids = undefined;
    } else {
      url = '/models';
    }
    return url;
  },

  fetch: function(args) {
    if (args.ids) {
      this.fetch_ids = args.ids;
    }
    return Backbone.Model.prototype.fetch.call(this, args);
  }
});

I think it keeps the functionality in the proper 'place', and it allows more reusability (ie, you can fetch(list_of_ids) any time... you don't need a new object)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜