diff --git a/backbone-relational.js b/backbone-relational.js index b4f3a81d..2b18d39e 100755 --- a/backbone-relational.js +++ b/backbone-relational.js @@ -1387,7 +1387,7 @@ * @param {string} key The relation key to fetch models for. * @param {Object} [options] Options for 'Backbone.Model.fetch' and 'Backbone.sync'. * @param {Boolean} [refresh=false] Fetch existing models from the server as well (in order to update them). - * @return {jQuery.when[]} An array of request objects. + * @return {jQuery.Deferred} A jQuery promise object */ fetchRelated: function( key, options, refresh ) { // Set default `options` for fetch @@ -1458,7 +1458,7 @@ } } - return requests; + return $.when.apply( null, requests ); }, set: function( key, value, options ) { diff --git a/index.html b/index.html index d18fb843..5a47913f 100644 --- a/index.html +++ b/index.html @@ -517,8 +517,8 @@
Determine the type of collections used for a HasMany relation. If you define a
url(models<Backbone.Model[]>) function on the specified collection, this enables
- fetchRelated
to fetch all missing models in one request, instead of
- firing a separate request for each.
+ fetchRelated
to fetch all missing models in one request,
+ instead of firing a separate request for each.
relationalModel.fetchRelated(key<string>, [options<object>], [refresh<boolean>])
- Returns: deferred[]
An array of (zero or more) request objects.
+ Returns: jQuery.Deferred
A jQuery promise
- Fetch models from the server that were referenced in the model's attributes, but have not been found/created yet.
- This can be used specifically for lazy-loading scenarios. Setting update to true guarantees that the model will
- be fetched from the server and any model that already exists in the store will be updated with the retrieved data.
- The options object specifies options to be passed to Backbone.Sync.
+ Fetch the models in a relation from the server. By default, only those models are fetched that were referenced in the attributes,
+ but have not been found/created yet. This can be used specifically for lazy-loading scenarios.
+ Setting refresh
to true will fetch all model(s) from the server. In that case, any model that already
+ exists will be updated with the retrieved data.
+ The options
object specifies options to be passed to Backbone.Sync.
- By default, a separate request will be fired for each additional model that is to be fetched from the server.
+ By default, a separate request will be fired for each model that is to be fetched from the server (if `key` references a collection).
However, if your server/API supports it, you can fetch the set of models in one request by specifying a
collectionType for the relation you call fetchRelated on. The collectionType
should have an overridden url
diff --git a/test/tests.js b/test/tests.js
index 5f07ee0c..c7a8fc87 100644
--- a/test/tests.js
+++ b/test/tests.js
@@ -959,19 +959,19 @@ $(document).ready(function() {
var idsToFetch = person.getIdsToFetch( 'user' );
deepEqual( idsToFetch, [ 'user-10' ] );
- var requests = person.fetchRelated( 'user', { error: function() {
+ var request = person.fetchRelated( 'user', { error: function() {
errorCount++;
}
});
- ok( _.isArray( requests ) );
- equal( requests.length, 1, "A request has been made" );
+ ok( _.isObject( request ) && request.always && request.done && request.fail );
+ equal( window.requests.length, 1, "A single request has been made" );
ok( person.get( 'user' ) instanceof User );
// Triggering the 'error' callback should destroy the model
- requests[ 0 ].error();
- // Trigger the 'success' callback to fire the 'destroy' event
- window.requests[ window.requests.length - 1 ].success();
+ window.requests[ 0 ].error();
+ // Trigger the 'success' callback on the `destroy` call to actually fire the 'destroy' event
+ _.last( window.requests ).success();
ok( !person.get( 'user' ), "User has been destroyed & removed" );
equal( errorCount, 1, "The error callback executed successfully" );
@@ -981,8 +981,8 @@ $(document).ready(function() {
resource_uri: 'person-11'
});
- requests = person2.fetchRelated( 'user' );
- equal( requests.length, 0, "No request was made" );
+ request = person2.fetchRelated( 'user' );
+ equal( window.requests.length, 1, "No request was made" );
});
test( "fetchRelated on a HasMany relation", function() {
@@ -997,14 +997,16 @@ $(document).ready(function() {
//
// Case 1: separate requests for each model
//
- var requests = zoo.fetchRelated( 'animals', { error: function() { errorCount++; } } );
- ok( _.isArray( requests ) );
- equal( requests.length, 2, "Two requests have been made (a separate one for each animal)" );
+ window.requests = [];
+ var request = zoo.fetchRelated( 'animals', { error: function() { errorCount++; } } );
+
+ ok( _.isObject( request ) && request.always && request.done && request.fail );
+ equal( window.requests.length, 2, "Two requests have been made (a separate one for each animal)" );
equal( zoo.get( 'animals' ).length, 3, "Three animals in the zoo" );
// Triggering the 'error' callback for one request should destroy the model
- requests[ 0 ].error();
- // Trigger the 'success' callback on the `destroy` call to fire the 'destroy' event
+ window.requests[ 0 ].error();
+ // Trigger the 'success' callback on the `destroy` call to actually fire the 'destroy' event
_.last( window.requests ).success();
equal( zoo.get( 'animals' ).length, 2, "Two animals left in the zoo" );
@@ -1014,7 +1016,9 @@ $(document).ready(function() {
// Case 2: one request per fetch (generated by the collection)
//
// Give 'zoo' a custom url function that builds a url to fetch a set of models from their ids
+ window.requests = [];
errorCount = 0;
+
zoo.get( 'animals' ).url = function( models ) {
return '/animal/' + ( models ? 'set/' + _.pluck( models, 'id' ).join(';') + '/' : '' );
};
@@ -1025,37 +1029,39 @@ $(document).ready(function() {
equal( zoo.get( 'animals' ).length, 1 );
// `fetchRelated` creates two placeholder models for the ids present in the relation.
- requests = zoo.fetchRelated( 'animals', { error: function() { errorCount++; } } );
+ window.requests = [];
+ request = zoo.fetchRelated( 'animals', { error: function() { errorCount++; } } );
- ok( _.isArray( requests ) );
- equal( requests.length, 1 );
- equal( requests[ 0 ].url, '/animal/set/lion-2;zebra-2/' );
- equal( zoo.get('animals').length, 3 );
+ ok( _.isObject( request ) && request.always && request.done && request.fail );
+ equal( window.requests.length, 1 );
+ equal( _.last( window.requests ).url, '/animal/set/lion-2;zebra-2/' );
+ equal( zoo.get('animals').length, 3, "Three animals in the zoo" );
// Triggering the 'error' callback (some error occured during fetching) should trigger the 'destroy' event
// on both fetched models, but should NOT actually make 'delete' requests to the server!
- var numRequests = window.requests.length;
- requests[ 0 ].error();
- ok( window.requests.length === numRequests, "An error occured when fetching, but no DELETE requests are made to the server while handling local cleanup." );
+ _.last( window.requests ).error();
+ equal( window.requests.length, 1, "An error occured when fetching, but no DELETE requests are made to the server while handling local cleanup." );
equal( zoo.get( 'animals' ).length, 1, "Both animals are destroyed" );
equal( errorCount, 2, "The error callback executed successfully for both models" );
// Try to re-fetch; nothing left to get though
- requests = zoo.fetchRelated( 'animals' );
+ window.requests = [];
+ request = zoo.fetchRelated( 'animals' );
- equal( requests.length, 0 );
+ equal( window.requests.length, 0 );
equal( zoo.get( 'animals' ).length, 1 );
// Re-fetch the existing model
- requests = zoo.fetchRelated( 'animals', null, true );
+ window.requests = [];
+ request = zoo.fetchRelated( 'animals', null, true );
- equal( requests.length, 1 );
- equal( requests[ 0 ].url, '/animal/set/monkey-1/' );
+ equal( window.requests.length, 1 );
+ equal( _.last( window.requests ).url, '/animal/set/monkey-1/' );
equal( zoo.get( 'animals' ).length, 1 );
// An error while refreshing an existing model shouldn't affect it
- requests[ 0 ].error();
+ window.requests[ 0 ].error();
equal( zoo.get( 'animals' ).length, 1 );
});