Backbone-relational
Backbone-relational copied to clipboard
Fetch Children of a Model
I don't know if there is currently a way to fetch all of the "children" of a relational model or not, but a few months ago I found a need to do this so created a little extension for Backbone Relational. I wanted to do this in order to not have to fetch the entire collection at once, but rather fetch a subset when needed.
Basically, I tweaked the .fetch()
method:
Backbone.RelationalModel.prototype.fetchChildren = function( key, options, update ){
options || ( options = {} );
var setUrl = null,
requests = [],
rel = this.getRelation( key ),
keyContents = rel && rel.keyContents;
//don't bother getting wineIds if we are going to force an update
var wineIds = null;
if (!update){
wineIds = _.pluck(Backbone.Relational.store.getCollection(rel.relatedModel), rel.keySource);
}
if ( update || _.contains(wineIds, keyContents) ) {
// Try if the 'collection' can provide a url to fetch a set of models in one request.
if ( rel.related instanceof Backbone.Collection && _.isFunction( rel.related.url ) ) {
setUrl = rel.related.url( this );
}
// An assumption is that when 'Backbone.Collection.url' is a function, it can handle building of set urls.
// To make sure it can, test if the url we got by supplying a list of models to fetch is different from
// the one supplied for the default fetch action (without args to 'url').
if ( setUrl && setUrl !== rel.related.url() ) {
var opts = _.defaults(
{
error: function(collection, xhr, options) {
console.log("error: " + xhr);
},
url: setUrl
},
options,
{ add: true }
);
requests = [ rel.related.fetch( opts ) ];
}
else {
console.log("error: setUrl && setUrl !== rel.related.url() == FALSE");
}
}
return requests;
};
This code depends on the model having URL that is a function that takes a model
as an argument, and returns a URL with that model's ID in the URL, with a backend that knows how to sort and return the applicable models. For example:
var TastingNoteCollection = Backbone.Collection.extend({
url: function(models){
var url = "/rest/WineCellar/tastingNotes";
if (models != undefined){
var wineId = models.get("wineId");
if (wineId != undefined && wineId != null){
url = "/rest/WineCellar/wines/" + wineId + "/tastingNotes";
}
}
return url;
},
model: TastingNoteModel,
initialize: function(){ }
});
I'm not sure if there is already a more preferred way to do this, but the above worked for me.