9292 * requests with credentials} for more information.
9393 * - **`responseType`** - `{string}` - see {@link
9494 * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
95+ * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
96+ * `response` and `responseError`. Both `response` and `responseError` interceptors get called
97+ * with `http response` object. See {@link ng.$http $http interceptors}.
9598 *
9699 * @returns {Object } A resource "class" object with methods for the default set of resource actions
97100 * optionally extended with custom `actions`. The default set contains these actions:
130133 * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
131134 * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
132135 *
136+ * Success callback is called with (value, responseHeaders) arguments. Error callback is called
137+ * with (httpResponse) argument.
133138 *
134- * The Resource instances and collection have these additional properties:
139+ * Class actions return empty instance (with additional properties below).
140+ * Instance actions return promise of the action.
135141 *
136- * - `$then`: the `then` method of a {@link ng.$q promise} derived from the underlying
137- * {@link ng.$http $http} call.
142+ * The Resource instances and collection have these additional properties:
138143 *
139- * The success callback for the `$then` method will be resolved if the underlying `$http` requests
140- * succeeds .
144+ * - `$promise`: the { @link ng.$q promise} of the original server interaction that created this
145+ * instance or collection .
141146 *
142- * The success callback is called with a single object which is the {@link ng.$http http response}
143- * object extended with a new property `resource`. This `resource` property is a reference to the
144- * result of the resource action — resource object or array of resources.
147+ * On success, the promise is resolved with the same resource instance or collection object,
148+ * updated with data from server. This makes it easy to use in
149+ * {@link ng.$routeProvider resolve section of $routeProvider.when()} to defer view rendering
150+ * until the resource(s) are loaded.
145151 *
146- * The error callback is called with the {@link ng.$http http response} object when an http
147- * error occurs .
152+ * On failure, the promise is resolved with the {@link ng.$http http response} object,
153+ * without the `resource` property .
148154 *
149- * - `$resolved`: true if the promise has been resolved (either with success or rejection);
150- * Knowing if the Resource has been resolved is useful in data-binding.
155+ * - `$resolved`: ` true` after first server interaction is completed (either with success or rejection),
156+ * `false` before that. Knowing if the Resource has been resolved is useful in data-binding.
151157 *
152158 * @example
153159 *
268274 </doc:example>
269275 */
270276angular . module ( 'ngResource' , [ 'ng' ] ) .
271- factory ( '$resource' , [ '$http' , '$parse' , function ( $http , $parse ) {
277+ factory ( '$resource' , [ '$http' , '$parse' , '$q' , function ( $http , $parse , $q ) {
272278 var DEFAULT_ACTIONS = {
273279 'get' : { method :'GET' } ,
274280 'save' : { method :'POST' } ,
@@ -398,19 +404,19 @@ angular.module('ngResource', ['ng']).
398404 return ids ;
399405 }
400406
407+ function defaultResponseInterceptor ( response ) {
408+ return response . resource ;
409+ }
410+
401411 function Resource ( value ) {
402412 copy ( value || { } , this ) ;
403413 }
404414
405415 forEach ( actions , function ( action , name ) {
406- action . method = angular . uppercase ( action . method ) ;
407- var hasBody = action . method == 'POST' || action . method == 'PUT' || action . method == 'PATCH' ;
416+ var hasBody = / ^ ( P O S T | P U T | P A T C H ) $ / i . test ( action . method ) ;
417+
408418 Resource [ name ] = function ( a1 , a2 , a3 , a4 ) {
409- var params = { } ;
410- var data ;
411- var success = noop ;
412- var error = null ;
413- var promise ;
419+ var params = { } , data , success , error ;
414420
415421 switch ( arguments . length ) {
416422 case 4 :
@@ -442,31 +448,28 @@ angular.module('ngResource', ['ng']).
442448 break ;
443449 case 0 : break ;
444450 default :
445- throw "Expected between 0- 4 arguments [params, data, success, error], got " +
451+ throw "Expected up to 4 arguments [params, data, success, error], got " +
446452 arguments . length + " arguments." ;
447453 }
448454
449- var value = this instanceof Resource ? this : ( action . isArray ? [ ] : new Resource ( data ) ) ;
450- var httpConfig = { } ,
451- promise ;
455+ var isInstanceCall = data instanceof Resource ;
456+ var value = isInstanceCall ? data : ( action . isArray ? [ ] : new Resource ( data ) ) ;
457+ var httpConfig = { } ;
458+ var responseInterceptor = action . interceptor && action . interceptor . response || defaultResponseInterceptor ;
459+ var responseErrorInterceptor = action . interceptor && action . interceptor . responseError || undefined ;
452460
453461 forEach ( action , function ( value , key ) {
454- if ( key != 'params' && key != 'isArray' ) {
462+ if ( key != 'params' && key != 'isArray' && key != 'interceptor' ) {
455463 httpConfig [ key ] = copy ( value ) ;
456464 }
457465 } ) ;
466+
458467 httpConfig . data = data ;
459468 route . setUrlParams ( httpConfig , extend ( { } , extractParams ( data , action . params || { } ) , params ) , action . url ) ;
460469
461- function markResolved ( ) { value . $resolved = true ; }
462-
463- promise = $http ( httpConfig ) ;
464- value . $resolved = false ;
465-
466- promise . then ( markResolved , markResolved ) ;
467- value . $then = promise . then ( function ( response ) {
468- var data = response . data ;
469- var then = value . $then , resolved = value . $resolved ;
470+ var promise = $http ( httpConfig ) . then ( function ( response ) {
471+ var data = response . data ,
472+ promise = value . $promise ;
470473
471474 if ( data ) {
472475 if ( action . isArray ) {
@@ -476,44 +479,47 @@ angular.module('ngResource', ['ng']).
476479 } ) ;
477480 } else {
478481 copy ( data , value ) ;
479- value . $then = then ;
480- value . $resolved = resolved ;
482+ value . $promise = promise ;
481483 }
482484 }
483485
486+ value . $resolved = true ;
487+
484488 ( success || noop ) ( value , response . headers ) ;
485489
486490 response . resource = value ;
491+
487492 return response ;
488- } , error ) . then ;
493+ } , function ( response ) {
494+ value . $resolved = true ;
489495
490- return value ;
491- } ;
496+ ( error || noop ) ( response ) ;
492497
498+ return $q . reject ( response ) ;
499+ } ) . then ( responseInterceptor , responseErrorInterceptor ) ;
493500
494- Resource . prototype [ '$' + name ] = function ( a1 , a2 , a3 ) {
495- var params = extractParams ( this ) ,
496- success = noop ,
497- error ;
498501
499- switch ( arguments . length ) {
500- case 3 : params = a1 ; success = a2 ; error = a3 ; break ;
501- case 2 :
502- case 1 :
503- if ( isFunction ( a1 ) ) {
504- success = a1 ;
505- error = a2 ;
506- } else {
507- params = a1 ;
508- success = a2 || noop ;
509- }
510- case 0 : break ;
511- default :
512- throw "Expected between 1-3 arguments [params, success, error], got " +
513- arguments . length + " arguments." ;
502+ if ( ! isInstanceCall ) {
503+ // we are creating instance / collection
504+ // - set the initial promise
505+ // - return the instance / collection
506+ value . $promise = promise ;
507+ value . $resolved = false ;
508+
509+ return value ;
510+ }
511+
512+ // instance call
513+ return promise ;
514+ } ;
515+
516+
517+ Resource . prototype [ '$' + name ] = function ( params , success , error ) {
518+ if ( isFunction ( params ) ) {
519+ error = success ; success = params ; params = { } ;
514520 }
515- var data = hasBody ? this : undefined ;
516- Resource [ name ] . call ( this , params , data , success , error ) ;
521+ var result = Resource [ name ] ( params , this , success , error ) ;
522+ return result . $promise || result ;
517523 } ;
518524 } ) ;
519525
0 commit comments