}` –
* transform function or an array of such functions. The transform function takes the http
* response body and headers and returns its transformed (typically deserialized) version.
+ * By default, transformResponse will contain one function that checks if the response looks like
+ * a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
+ * `transformResponse` to an empty array: `transformResponse: []`
* - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
* GET request, otherwise if a cache instance built with
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
@@ -98,35 +158,45 @@ var $resourceMinErr = angular.$$minErr('$resource');
* - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
* should abort the request when resolved.
* - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
- * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
- * requests with credentials} for more information.
- * - **`responseType`** - `{string}` - see {@link
- * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
+ * XHR object. See
+ * [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
+ * for more information.
+ * - **`responseType`** - `{string}` - see
+ * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
* - **`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}.
*
+ * @param {Object} options Hash with custom settings that should extend the
+ * default `$resourceProvider` behavior. The only supported option is
+ *
+ * Where:
+ *
+ * - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
+ * slashes from any calculated URL will be stripped. (Defaults to true.)
+ *
* @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:
- *
- * { 'get': {method:'GET'},
- * 'save': {method:'POST'},
- * 'query': {method:'GET', isArray:true},
- * 'remove': {method:'DELETE'},
- * 'delete': {method:'DELETE'} };
+ * ```js
+ * { 'get': {method:'GET'},
+ * 'save': {method:'POST'},
+ * 'query': {method:'GET', isArray:true},
+ * 'remove': {method:'DELETE'},
+ * 'delete': {method:'DELETE'} };
+ * ```
*
* Calling these methods invoke an {@link ng.$http} with the specified http method,
* destination and parameters. When the data is returned from the server then the object is an
* instance of the resource class. The actions `save`, `remove` and `delete` are available on it
* as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
* read, update, delete) on server-side data like this:
- *
- var User = $resource('/user/:userId', {userId:'@id'});
- var user = User.get({userId:123}, function() {
- user.abc = true;
- user.$save();
- });
-
+ * ```js
+ * var User = $resource('/user/:userId', {userId:'@id'});
+ * var user = User.get({userId:123}, function() {
+ * user.abc = true;
+ * user.$save();
+ * });
+ * ```
*
* It is important to realize that invoking a $resource object method immediately returns an
* empty reference (object or array depending on `isArray`). Once the data is returned from the
@@ -134,7 +204,7 @@ var $resourceMinErr = angular.$$minErr('$resource');
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
* object results in no rendering, once the data arrives from the server then the object is
* populated with the data and the view automatically re-renders itself showing the new data. This
- * means that in most case one never has to write a callback function for the action methods.
+ * means that in most cases one never has to write a callback function for the action methods.
*
* The action methods on the class object or instance object can be invoked with the following
* parameters:
@@ -162,6 +232,9 @@ var $resourceMinErr = angular.$$minErr('$resource');
* On failure, the promise is resolved with the {@link ng.$http http response} object, without
* the `resource` property.
*
+ * If an interceptor object was provided, the promise will instead be resolved with the value
+ * returned by the interceptor.
+ *
* - `$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.
@@ -170,7 +243,7 @@ var $resourceMinErr = angular.$$minErr('$resource');
*
* # Credit card resource
*
- *
+ * ```js
// Define CreditCard class
var CreditCard = $resource('/user/:userId/card/:cardId',
{userId:123, cardId:'@id'}, {
@@ -201,9 +274,9 @@ var $resourceMinErr = angular.$$minErr('$resource');
newCard.name = "Mike Smith";
newCard.$save();
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
- // server returns: {id:789, number:'01234', name: 'Mike Smith'};
+ // server returns: {id:789, number:'0123', name: 'Mike Smith'};
expect(newCard.id).toEqual(789);
- *
+ * ```
*
* The object returned from this function execution is a resource "class" which has "static" method
* for each action in the definition.
@@ -214,19 +287,19 @@ var $resourceMinErr = angular.$$minErr('$resource');
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
* operations (create, read, update, delete) on server-side data.
-
+ ```js
var User = $resource('/user/:userId', {userId:'@id'});
- var user = User.get({userId:123}, function() {
+ User.get({userId:123}, function(user) {
user.abc = true;
user.$save();
});
-
+ ```
*
* It's worth noting that the success callback for `get`, `query` and other methods gets passed
* in the response that came from the server as well as $http header getter function, so one
* could rewrite the above example and get access to http headers as:
*
-
+ ```js
var User = $resource('/user/:userId', {userId:'@id'});
User.get({userId:123}, function(u, getResponseHeaders){
u.abc = true;
@@ -235,344 +308,360 @@ var $resourceMinErr = angular.$$minErr('$resource');
//putResponseHeaders => $http header getter
});
});
-
-
- * # Buzz client
-
- Let's look at what a buzz client created with the `$resource` service looks like:
-
-
-
-
-
-
-
fetch
-
-
-
- {{item.object.content | html}}
-
-
-
-
-
-
-
+ ```
+ *
+ * You can also access the raw `$http` promise via the `$promise` property on the object returned
+ *
+ ```
+ var User = $resource('/user/:userId', {userId:'@id'});
+ User.get({userId:123})
+ .$promise.then(function(user) {
+ $scope.user = user;
+ });
+ ```
+
+ * # Creating a custom 'PUT' request
+ * In this example we create a custom method on our resource to make a PUT request
+ * ```js
+ * var app = angular.module('app', ['ngResource', 'ngRoute']);
+ *
+ * // Some APIs expect a PUT request in the format URL/object/ID
+ * // Here we are creating an 'update' method
+ * app.factory('Notes', ['$resource', function($resource) {
+ * return $resource('/notes/:id', null,
+ * {
+ * 'update': { method:'PUT' }
+ * });
+ * }]);
+ *
+ * // In our controller we get the ID from the URL using ngRoute and $routeParams
+ * // We pass in $routeParams and our Notes factory along with $scope
+ * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
+ function($scope, $routeParams, Notes) {
+ * // First get a note object from the factory
+ * var note = Notes.get({ id:$routeParams.id });
+ * $id = note.id;
+ *
+ * // Now call update passing in the ID first then the object you are updating
+ * Notes.update({ id:$id }, note);
+ *
+ * // This will PUT /notes/ID with the note object in the request payload
+ * }]);
+ * ```
*/
angular.module('ngResource', ['ng']).
- factory('$resource', ['$http', '$parse', '$q', function($http, $parse, $q) {
- var DEFAULT_ACTIONS = {
- 'get': {method:'GET'},
- 'save': {method:'POST'},
- 'query': {method:'GET', isArray:true},
- 'remove': {method:'DELETE'},
- 'delete': {method:'DELETE'}
+ provider('$resource', function() {
+ var provider = this;
+
+ this.defaults = {
+ // Strip slashes by default
+ stripTrailingSlashes: true,
+
+ // Default actions configuration
+ actions: {
+ 'get': {method: 'GET'},
+ 'save': {method: 'POST'},
+ 'query': {method: 'GET', isArray: true},
+ 'remove': {method: 'DELETE'},
+ 'delete': {method: 'DELETE'}
+ }
};
- var noop = angular.noop,
+
+ this.$get = ['$http', '$q', function($http, $q) {
+
+ var noop = angular.noop,
forEach = angular.forEach,
extend = angular.extend,
copy = angular.copy,
- isFunction = angular.isFunction,
- getter = function(obj, path) {
- return $parse(path)(obj);
- };
-
- /**
- * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
- * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
- * segments:
- * segment = *pchar
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- * pct-encoded = "%" HEXDIG HEXDIG
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- * / "*" / "+" / "," / ";" / "="
- */
- function encodeUriSegment(val) {
- return encodeUriQuery(val, true).
- replace(/%26/gi, '&').
- replace(/%3D/gi, '=').
- replace(/%2B/gi, '+');
- }
+ isFunction = angular.isFunction;
+
+ /**
+ * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
+ * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
+ * (pchar) allowed in path segments:
+ * segment = *pchar
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ * / "*" / "+" / "," / ";" / "="
+ */
+ function encodeUriSegment(val) {
+ return encodeUriQuery(val, true).
+ replace(/%26/gi, '&').
+ replace(/%3D/gi, '=').
+ replace(/%2B/gi, '+');
+ }
- /**
- * This method is intended for encoding *key* or *value* parts of query component. We need a
- * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
- * have to be encoded per http://tools.ietf.org/html/rfc3986:
- * query = *( pchar / "/" / "?" )
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * pct-encoded = "%" HEXDIG HEXDIG
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- * / "*" / "+" / "," / ";" / "="
- */
- function encodeUriQuery(val, pctEncodeSpaces) {
- return encodeURIComponent(val).
- replace(/%40/gi, '@').
- replace(/%3A/gi, ':').
- replace(/%24/g, '$').
- replace(/%2C/gi, ',').
- replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
- }
+ /**
+ * This method is intended for encoding *key* or *value* parts of query component. We need a
+ * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
+ * have to be encoded per http://tools.ietf.org/html/rfc3986:
+ * query = *( pchar / "/" / "?" )
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ * / "*" / "+" / "," / ";" / "="
+ */
+ function encodeUriQuery(val, pctEncodeSpaces) {
+ return encodeURIComponent(val).
+ replace(/%40/gi, '@').
+ replace(/%3A/gi, ':').
+ replace(/%24/g, '$').
+ replace(/%2C/gi, ',').
+ replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
+ }
- function Route(template, defaults) {
- this.template = template;
- this.defaults = defaults || {};
- this.urlParams = {};
- }
+ function Route(template, defaults) {
+ this.template = template;
+ this.defaults = extend({}, provider.defaults, defaults);
+ this.urlParams = {};
+ }
- Route.prototype = {
- setUrlParams: function(config, params, actionUrl) {
- var self = this,
+ Route.prototype = {
+ setUrlParams: function(config, params, actionUrl) {
+ var self = this,
url = actionUrl || self.template,
val,
encodedVal;
- var urlParams = self.urlParams = {};
- forEach(url.split(/\W/), function(param){
- if (param === 'hasOwnProperty') {
- throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
- }
- if (!(new RegExp("^\\d+$").test(param)) && param &&
- (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
- urlParams[param] = true;
- }
- });
- url = url.replace(/\\:/g, ':');
-
- params = params || {};
- forEach(self.urlParams, function(_, urlParam){
- val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
- if (angular.isDefined(val) && val !== null) {
- encodedVal = encodeUriSegment(val);
- url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1");
- } else {
- url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
- leadingSlashes, tail) {
- if (tail.charAt(0) == '/') {
- return tail;
- } else {
- return leadingSlashes + tail;
- }
- });
- }
- });
+ var urlParams = self.urlParams = {};
+ forEach(url.split(/\W/), function(param) {
+ if (param === 'hasOwnProperty') {
+ throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
+ }
+ if (!(new RegExp("^\\d+$").test(param)) && param &&
+ (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
+ urlParams[param] = true;
+ }
+ });
+ url = url.replace(/\\:/g, ':');
+
+ params = params || {};
+ forEach(self.urlParams, function(_, urlParam) {
+ val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
+ if (angular.isDefined(val) && val !== null) {
+ encodedVal = encodeUriSegment(val);
+ url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
+ return encodedVal + p1;
+ });
+ } else {
+ url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
+ leadingSlashes, tail) {
+ if (tail.charAt(0) == '/') {
+ return tail;
+ } else {
+ return leadingSlashes + tail;
+ }
+ });
+ }
+ });
- // strip trailing slashes and set the url
- url = url.replace(/\/+$/, '');
- // then replace collapse `/.` if found in the last URL path segment before the query
- // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
- url = url.replace(/\/\.(?=\w+($|\?))/, '.');
- // replace escaped `/\.` with `/.`
- config.url = url.replace(/\/\\\./, '/.');
+ // strip trailing slashes and set the url (unless this behavior is specifically disabled)
+ if (self.defaults.stripTrailingSlashes) {
+ url = url.replace(/\/+$/, '') || '/';
+ }
+ // then replace collapse `/.` if found in the last URL path segment before the query
+ // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
+ url = url.replace(/\/\.(?=\w+($|\?))/, '.');
+ // replace escaped `/\.` with `/.`
+ config.url = url.replace(/\/\\\./, '/.');
- // set params - delegate param encoding to $http
- forEach(params, function(value, key){
- if (!self.urlParams[key]) {
- config.params = config.params || {};
- config.params[key] = value;
- }
- });
- }
- };
+ // set params - delegate param encoding to $http
+ forEach(params, function(value, key) {
+ if (!self.urlParams[key]) {
+ config.params = config.params || {};
+ config.params[key] = value;
+ }
+ });
+ }
+ };
- function resourceFactory(url, paramDefaults, actions) {
- var route = new Route(url);
- actions = extend({}, DEFAULT_ACTIONS, actions);
+ function resourceFactory(url, paramDefaults, actions, options) {
+ var route = new Route(url, options);
- function extractParams(data, actionParams){
- var ids = {};
- actionParams = extend({}, paramDefaults, actionParams);
- forEach(actionParams, function(value, key){
- if (isFunction(value)) { value = value(); }
- ids[key] = value && value.charAt && value.charAt(0) == '@' ?
- getter(data, value.substr(1)) : value;
- });
- return ids;
- }
+ actions = extend({}, provider.defaults.actions, actions);
- function defaultResponseInterceptor(response) {
- return response.resource;
- }
+ function extractParams(data, actionParams) {
+ var ids = {};
+ actionParams = extend({}, paramDefaults, actionParams);
+ forEach(actionParams, function(value, key) {
+ if (isFunction(value)) { value = value(); }
+ ids[key] = value && value.charAt && value.charAt(0) == '@' ?
+ lookupDottedPath(data, value.substr(1)) : value;
+ });
+ return ids;
+ }
+
+ function defaultResponseInterceptor(response) {
+ return response.resource;
+ }
+
+ function Resource(value) {
+ shallowClearAndCopy(value || {}, this);
+ }
+
+ Resource.prototype.toJSON = function() {
+ var data = extend({}, this);
+ delete data.$promise;
+ delete data.$resolved;
+ return data;
+ };
- function Resource(value){
- copy(value || {}, this);
- }
+ forEach(actions, function(action, name) {
+ var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
- forEach(actions, function(action, name) {
- var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
-
- Resource[name] = function(a1, a2, a3, a4) {
- var params = {}, data, success, error;
-
- /* jshint -W086 */ /* (purposefully fall through case statements) */
- switch(arguments.length) {
- case 4:
- error = a4;
- success = a3;
- //fallthrough
- case 3:
- case 2:
- if (isFunction(a2)) {
- if (isFunction(a1)) {
- success = a1;
- error = a2;
- break;
- }
+ Resource[name] = function(a1, a2, a3, a4) {
+ var params = {}, data, success, error;
- success = a2;
- error = a3;
+ /* jshint -W086 */ /* (purposefully fall through case statements) */
+ switch (arguments.length) {
+ case 4:
+ error = a4;
+ success = a3;
//fallthrough
- } else {
- params = a1;
- data = a2;
- success = a3;
- break;
- }
- case 1:
- if (isFunction(a1)) success = a1;
- else if (hasBody) data = a1;
- else params = a1;
- break;
- case 0: break;
- default:
- throw $resourceMinErr('badargs',
- "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
- arguments.length);
- }
- /* jshint +W086 */ /* (purposefully fall through case statements) */
-
- 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' && key != 'interceptor') {
- httpConfig[key] = copy(value);
+ case 3:
+ case 2:
+ if (isFunction(a2)) {
+ if (isFunction(a1)) {
+ success = a1;
+ error = a2;
+ break;
+ }
+
+ success = a2;
+ error = a3;
+ //fallthrough
+ } else {
+ params = a1;
+ data = a2;
+ success = a3;
+ break;
+ }
+ case 1:
+ if (isFunction(a1)) success = a1;
+ else if (hasBody) data = a1;
+ else params = a1;
+ break;
+ case 0: break;
+ default:
+ throw $resourceMinErr('badargs',
+ "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
+ arguments.length);
}
- });
+ /* jshint +W086 */ /* (purposefully fall through case statements) */
+
+ var isInstanceCall = this 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' && key != 'interceptor') {
+ httpConfig[key] = copy(value);
+ }
+ });
- if (hasBody) httpConfig.data = data;
- route.setUrlParams(httpConfig,
- extend({}, extractParams(data, action.params || {}), params),
- action.url);
+ if (hasBody) httpConfig.data = data;
+ route.setUrlParams(httpConfig,
+ extend({}, extractParams(data, action.params || {}), params),
+ action.url);
- var promise = $http(httpConfig).then(function(response) {
- var data = response.data,
+ var promise = $http(httpConfig).then(function(response) {
+ var data = response.data,
promise = value.$promise;
- if (data) {
- // Need to convert action.isArray to boolean in case it is undefined
- // jshint -W018
- if ( angular.isArray(data) !== (!!action.isArray) ) {
- throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
- 'response to contain an {0} but got an {1}',
- action.isArray?'array':'object', angular.isArray(data)?'array':'object');
- }
- // jshint +W018
- if (action.isArray) {
- value.length = 0;
- forEach(data, function(item) {
- value.push(new Resource(item));
- });
- } else {
- copy(data, value);
- value.$promise = promise;
+ if (data) {
+ // Need to convert action.isArray to boolean in case it is undefined
+ // jshint -W018
+ if (angular.isArray(data) !== (!!action.isArray)) {
+ throw $resourceMinErr('badcfg',
+ 'Error in resource configuration for action `{0}`. Expected response to ' +
+ 'contain an {1} but got an {2}', name, action.isArray ? 'array' : 'object',
+ angular.isArray(data) ? 'array' : 'object');
+ }
+ // jshint +W018
+ if (action.isArray) {
+ value.length = 0;
+ forEach(data, function(item) {
+ if (typeof item === "object") {
+ value.push(new Resource(item));
+ } else {
+ // Valid JSON values may be string literals, and these should not be converted
+ // into objects. These items will not have access to the Resource prototype
+ // methods, but unfortunately there
+ value.push(item);
+ }
+ });
+ } else {
+ shallowClearAndCopy(data, value);
+ value.$promise = promise;
+ }
}
- }
- value.$resolved = true;
+ value.$resolved = true;
- response.resource = value;
+ response.resource = value;
- return response;
- }, function(response) {
- value.$resolved = true;
+ return response;
+ }, function(response) {
+ value.$resolved = true;
- (error||noop)(response);
+ (error || noop)(response);
- return $q.reject(response);
- });
+ return $q.reject(response);
+ });
- promise = promise.then(
+ promise = promise.then(
function(response) {
var value = responseInterceptor(response);
- (success||noop)(value, response.headers);
+ (success || noop)(value, response.headers);
return value;
},
responseErrorInterceptor);
- if (!isInstanceCall) {
- // we are creating instance / collection
- // - set the initial promise
- // - return the instance / collection
- value.$promise = promise;
- value.$resolved = false;
+ if (!isInstanceCall) {
+ // we are creating instance / collection
+ // - set the initial promise
+ // - return the instance / collection
+ value.$promise = promise;
+ value.$resolved = false;
- return value;
- }
+ return value;
+ }
- // instance call
- return promise;
- };
+ // instance call
+ return promise;
+ };
- Resource.prototype['$' + name] = function(params, success, error) {
- if (isFunction(params)) {
- error = success; success = params; params = {};
- }
- var result = Resource[name](params, this, success, error);
- return result.$promise || result;
- };
- });
+ Resource.prototype['$' + name] = function(params, success, error) {
+ if (isFunction(params)) {
+ error = success; success = params; params = {};
+ }
+ var result = Resource[name].call(this, params, this, success, error);
+ return result.$promise || result;
+ };
+ });
- Resource.bind = function(additionalParamDefaults){
- return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
- };
+ Resource.bind = function(additionalParamDefaults) {
+ return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
+ };
- return Resource;
- }
+ return Resource;
+ }
- return resourceFactory;
- }]);
+ return resourceFactory;
+ }];
+ });
})(window, window.angular);
diff --git a/angular-resource.min.js b/angular-resource.min.js
old mode 100755
new mode 100644
index 9d0959f..3448d6f
--- a/angular-resource.min.js
+++ b/angular-resource.min.js
@@ -1,12 +1,13 @@
/*
- AngularJS v1.2.0
- (c) 2010-2012 Google, Inc. http://angularjs.org
+ AngularJS v1.3.1
+ (c) 2010-2014 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(H,h,C){'use strict';var x=h.$$minErr("$resource");h.module("ngResource",["ng"]).factory("$resource",["$http","$parse","$q",function(D,y,E){function n(h,k){this.template=h;this.defaults=k||{};this.urlParams={}}function t(e,k,f){function q(b,c){var d={};c=u({},k,c);r(c,function(a,c){s(a)&&(a=a());var m;a&&a.charAt&&"@"==a.charAt(0)?(m=a.substr(1),m=y(m)(b)):m=a;d[c]=m});return d}function d(b){return b.resource}function g(b){z(b||{},this)}var F=new n(e);f=u({},G,f);r(f,function(b,c){var A=
-/^(POST|PUT|PATCH)$/i.test(b.method);g[c]=function(a,c,m,k){var p={},e,f,v;switch(arguments.length){case 4:v=k,f=m;case 3:case 2:if(s(c)){if(s(a)){f=a;v=c;break}f=c;v=m}else{p=a;e=c;f=m;break}case 1:s(a)?f=a:A?e=a:p=a;break;case 0:break;default:throw x("badargs",arguments.length);}var n=e instanceof g,l=n?e:b.isArray?[]:new g(e),w={},t=b.interceptor&&b.interceptor.response||d,y=b.interceptor&&b.interceptor.responseError||C;r(b,function(a,c){"params"!=c&&("isArray"!=c&&"interceptor"!=c)&&(w[c]=z(a))});
-A&&(w.data=e);F.setUrlParams(w,u({},q(e,b.params||{}),p),b.url);p=D(w).then(function(c){var a=c.data,d=l.$promise;if(a){if(h.isArray(a)!==!!b.isArray)throw x("badcfg",b.isArray?"array":"object",h.isArray(a)?"array":"object");b.isArray?(l.length=0,r(a,function(a){l.push(new g(a))})):(z(a,l),l.$promise=d)}l.$resolved=!0;c.resource=l;return c},function(a){l.$resolved=!0;(v||B)(a);return E.reject(a)});p=p.then(function(a){var c=t(a);(f||B)(c,a.headers);return c},y);return n?p:(l.$promise=p,l.$resolved=
-!1,l)};g.prototype["$"+c]=function(a,b,d){s(a)&&(d=b,b=a,a={});a=g[c](a,this,b,d);return a.$promise||a}});g.bind=function(b){return t(e,u({},k,b),f)};return g}var G={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},B=h.noop,r=h.forEach,u=h.extend,z=h.copy,s=h.isFunction;n.prototype={setUrlParams:function(e,k,f){var q=this,d=f||q.template,g,n,b=q.urlParams={};r(d.split(/\W/),function(c){if("hasOwnProperty"===c)throw x("badname");
-!/^\d+$/.test(c)&&(c&&RegExp("(^|[^\\\\]):"+c+"(\\W|$)").test(d))&&(b[c]=!0)});d=d.replace(/\\:/g,":");k=k||{};r(q.urlParams,function(c,b){g=k.hasOwnProperty(b)?k[b]:q.defaults[b];h.isDefined(g)&&null!==g?(n=encodeURIComponent(g).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),d=d.replace(RegExp(":"+b+"(\\W|$)","g"),n+"$1")):d=d.replace(RegExp("(/?):"+b+"(\\W|$)","g"),function(a,
-c,b){return"/"==b.charAt(0)?b:c+b})});d=d.replace(/\/+$/,"");d=d.replace(/\/\.(?=\w+($|\?))/,".");e.url=d.replace(/\/\\\./,"/.");r(k,function(c,b){q.urlParams[b]||(e.params=e.params||{},e.params[b]=c)})}};return t}])})(window,window.angular);
+(function(I,d,B){'use strict';function D(f,q){q=q||{};d.forEach(q,function(d,h){delete q[h]});for(var h in f)!f.hasOwnProperty(h)||"$"===h.charAt(0)&&"$"===h.charAt(1)||(q[h]=f[h]);return q}var w=d.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;d.module("ngResource",["ng"]).provider("$resource",function(){var f=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}}};
+this.$get=["$http","$q",function(q,h){function t(d,g){this.template=d;this.defaults=s({},f.defaults,g);this.urlParams={}}function v(x,g,l,m){function c(b,k){var c={};k=s({},g,k);r(k,function(a,k){u(a)&&(a=a());var d;if(a&&a.charAt&&"@"==a.charAt(0)){d=b;var e=a.substr(1);if(null==e||""===e||"hasOwnProperty"===e||!C.test("."+e))throw w("badmember",e);for(var e=e.split("."),n=0,g=e.length;n