aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ngResource/resource.js126
1 files changed, 66 insertions, 60 deletions
diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js
index 59ac3b3a..abb2bc56 100644
--- a/src/ngResource/resource.js
+++ b/src/ngResource/resource.js
@@ -92,6 +92,9 @@
* requests with credentials} for more information.
* - **`responseType`** - `{string}` - see {@link
* https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
+ * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
+ * `response` and `responseError`. Both `response` and `responseError` interceptors get called
+ * with `http response` object. See {@link ng.$http $http interceptors}.
*
* @returns {Object} A resource "class" object with methods for the default set of resource actions
* optionally extended with custom `actions`. The default set contains these actions:
@@ -130,24 +133,27 @@
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
*
+ * Success callback is called with (value, responseHeaders) arguments. Error callback is called
+ * with (httpResponse) argument.
*
- * The Resource instances and collection have these additional properties:
+ * Class actions return empty instance (with additional properties below).
+ * Instance actions return promise of the action.
*
- * - `$then`: the `then` method of a {@link ng.$q promise} derived from the underlying
- * {@link ng.$http $http} call.
+ * The Resource instances and collection have these additional properties:
*
- * The success callback for the `$then` method will be resolved if the underlying `$http` requests
- * succeeds.
+ * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
+ * instance or collection.
*
- * The success callback is called with a single object which is the {@link ng.$http http response}
- * object extended with a new property `resource`. This `resource` property is a reference to the
- * result of the resource action — resource object or array of resources.
+ * On success, the promise is resolved with the same resource instance or collection object,
+ * updated with data from server. This makes it easy to use in
+ * {@link ng.$routeProvider resolve section of $routeProvider.when()} to defer view rendering
+ * until the resource(s) are loaded.
*
- * The error callback is called with the {@link ng.$http http response} object when an http
- * error occurs.
+ * On failure, the promise is resolved with the {@link ng.$http http response} object,
+ * without the `resource` property.
*
- * - `$resolved`: true if the promise has been resolved (either with success or rejection);
- * Knowing if the Resource has been resolved is useful in data-binding.
+ * - `$resolved`: `true` after first server interaction is completed (either with success or rejection),
+ * `false` before that. Knowing if the Resource has been resolved is useful in data-binding.
*
* @example
*
@@ -268,7 +274,7 @@
</doc:example>
*/
angular.module('ngResource', ['ng']).
- factory('$resource', ['$http', '$parse', function($http, $parse) {
+ factory('$resource', ['$http', '$parse', '$q', function($http, $parse, $q) {
var DEFAULT_ACTIONS = {
'get': {method:'GET'},
'save': {method:'POST'},
@@ -398,19 +404,19 @@ angular.module('ngResource', ['ng']).
return ids;
}
+ function defaultResponseInterceptor(response) {
+ return response.resource;
+ }
+
function Resource(value){
copy(value || {}, this);
}
forEach(actions, function(action, name) {
- action.method = angular.uppercase(action.method);
- var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH';
+ var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
+
Resource[name] = function(a1, a2, a3, a4) {
- var params = {};
- var data;
- var success = noop;
- var error = null;
- var promise;
+ var params = {}, data, success, error;
switch(arguments.length) {
case 4:
@@ -442,31 +448,28 @@ angular.module('ngResource', ['ng']).
break;
case 0: break;
default:
- throw "Expected between 0-4 arguments [params, data, success, error], got " +
+ throw "Expected up to 4 arguments [params, data, success, error], got " +
arguments.length + " arguments.";
}
- var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
- var httpConfig = {},
- promise;
+ var isInstanceCall = data instanceof Resource;
+ var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
+ var httpConfig = {};
+ var responseInterceptor = action.interceptor && action.interceptor.response || defaultResponseInterceptor;
+ var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || undefined;
forEach(action, function(value, key) {
- if (key != 'params' && key != 'isArray' ) {
+ if (key != 'params' && key != 'isArray' && key != 'interceptor') {
httpConfig[key] = copy(value);
}
});
+
httpConfig.data = data;
route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), action.url);
- function markResolved() { value.$resolved = true; }
-
- promise = $http(httpConfig);
- value.$resolved = false;
-
- promise.then(markResolved, markResolved);
- value.$then = promise.then(function(response) {
- var data = response.data;
- var then = value.$then, resolved = value.$resolved;
+ var promise = $http(httpConfig).then(function(response) {
+ var data = response.data,
+ promise = value.$promise;
if (data) {
if (action.isArray) {
@@ -476,44 +479,47 @@ angular.module('ngResource', ['ng']).
});
} else {
copy(data, value);
- value.$then = then;
- value.$resolved = resolved;
+ value.$promise = promise;
}
}
+ value.$resolved = true;
+
(success||noop)(value, response.headers);
response.resource = value;
+
return response;
- }, error).then;
+ }, function(response) {
+ value.$resolved = true;
- return value;
- };
+ (error||noop)(response);
+ return $q.reject(response);
+ }).then(responseInterceptor, responseErrorInterceptor);
- Resource.prototype['$' + name] = function(a1, a2, a3) {
- var params = extractParams(this),
- success = noop,
- error;
- switch(arguments.length) {
- case 3: params = a1; success = a2; error = a3; break;
- case 2:
- case 1:
- if (isFunction(a1)) {
- success = a1;
- error = a2;
- } else {
- params = a1;
- success = a2 || noop;
- }
- case 0: break;
- default:
- throw "Expected between 1-3 arguments [params, success, error], got " +
- arguments.length + " arguments.";
+ if (!isInstanceCall) {
+ // we are creating instance / collection
+ // - set the initial promise
+ // - return the instance / collection
+ value.$promise = promise;
+ value.$resolved = false;
+
+ return value;
+ }
+
+ // instance call
+ return promise;
+ };
+
+
+ Resource.prototype['$' + name] = function(params, success, error) {
+ if (isFunction(params)) {
+ error = success; success = params; params = {};
}
- var data = hasBody ? this : undefined;
- Resource[name].call(this, params, data, success, error);
+ var result = Resource[name](params, this, success, error);
+ return result.$promise || result;
};
});