I would like to use a single Backbone Model that is composed of data from different URL endpoints. Is it possible to specify multiple URLs within a single model? I'd like to avoid calling AJAX by hand.
Until now, I've been using jQuery Deferreds to call multiple URLs and synthesize their results into a single object.
I can think of two options so far: building a Backbone model with a partial model for each URL, or using one URL and then overriding Model.fetch()
to call the other URLs. But neither one makes me comfortable.
(Or I can try to bribe the API developer to provide a merged URL endpoint...)
I think both of the ways you suggested are quite reasonable, but personally I'd vote for the fetch
approach.
Using nested models has the advantage of working "out of the box"; in other words, by using one model for every server <=> client mapping you avoid having to change any Backbone.Model
methods. The problem with this approach though is that you wind up with a conglomeration of multiple models.
If that makes sense anyway (data retrieval aside) then stick to nested models. But if not you're forcing the rest of your code to work with several models instead of just one solely to keep your data retrieval code simple. If you'd rather just complicate the data retrieval code and keep everything else simple then you're better off overwriting fetch
.
fetch
does one thing, and that is retrieve data via a one-to-one mapping between it and a remote URL. If you want a one-to-many mapping instead it makes perfect sense to just override the default fetch
behavior. Plus you know it's reasonably safe to override fetch
because it's name isn't _fetch
, and Backbone uses the the underscore style to name it's pseudo-private methods (eg. _validate
).
If you still don't like either of those approaches, there is one other option: request
events. The latest version of Backbone has a new event called request
that is triggered whenever a fetch
is started. What this means is that you can setup an event handler that retrieves your secondary data in response to the primary data's request, like so:
Backbone.Model.extend({
initialize: function() {
this.on('request', this.handleRequest);
_.bindAll(this, 'handleTriggeredResponse');
},
handleRequest: function() {
$.ajax({url: secondDataUrl, complete: this.handleTriggeredResponse});
$.ajax({url: tertiaryDataUrl, complete: this.handleTriggeredResponse});
},
handleTriggeredResponse: function(response) {
this.set(response.data);
},
url: firstDataUrl
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With