Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 60f1f09

Browse files
nolazybitsIgorMinar
authored andcommitted
feat($resource): ability to override url in resource actions
Resources now can defined per action url override. The url is treated as a template rather than a literal string, so fancy interpolations are possible. See attached tests for example usage.
1 parent cf17c6a commit 60f1f09

File tree

2 files changed

+79
-13
lines changed

2 files changed

+79
-13
lines changed

src/ngResource/resource.js

+17-13
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
* - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of the
5454
* parameter value is a function, it will be executed every time when a param value needs to be
5555
* obtained for a request (unless the param was overriden).
56+
* - **`url`** – {string} – action specific `url` override. The url templating is supported just like
57+
* for the resource-level urls.
5658
* - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, see
5759
* `returns` section.
5860
* - **`transformRequest`** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
@@ -306,30 +308,32 @@ angular.module('ngResource', ['ng']).
306308
function Route(template, defaults) {
307309
this.template = template = template + '#';
308310
this.defaults = defaults || {};
309-
var urlParams = this.urlParams = {};
310-
forEach(template.split(/\W/), function(param){
311-
if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) {
312-
urlParams[param] = true;
313-
}
314-
});
315-
this.template = template.replace(/\\:/g, ':');
311+
this.urlParams = {};
316312
}
317313

318314
Route.prototype = {
319-
setUrlParams: function(config, params) {
315+
setUrlParams: function(config, params, actionUrl) {
320316
var self = this,
321-
url = this.template,
317+
url = actionUrl || self.template,
322318
val,
323319
encodedVal;
324320

321+
var urlParams = self.urlParams = {};
322+
forEach(url.split(/\W/), function(param){
323+
if (param && (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
324+
urlParams[param] = true;
325+
}
326+
});
327+
url = url.replace(/\\:/g, ':');
328+
325329
params = params || {};
326-
forEach(this.urlParams, function(_, urlParam){
330+
forEach(self.urlParams, function(_, urlParam){
327331
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
328332
if (angular.isDefined(val) && val !== null) {
329333
encodedVal = encodeUriSegment(val);
330-
url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
334+
url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1");
331335
} else {
332-
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match,
336+
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
333337
leadingSlashes, tail) {
334338
if (tail.charAt(0) == '/') {
335339
return tail;
@@ -427,7 +431,7 @@ angular.module('ngResource', ['ng']).
427431
}
428432
});
429433
httpConfig.data = data;
430-
route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params));
434+
route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), action.url);
431435

432436
function markResolved() { value.$resolved = true; }
433437

test/ngResource/resourceSpec.js

+62
Original file line numberDiff line numberDiff line change
@@ -703,4 +703,66 @@ describe("resource", function() {
703703
$httpBackend.flush();
704704
expect(person.id).toEqual(456);
705705
});
706+
707+
708+
describe('action-level url override', function() {
709+
710+
it('should support overriding url template with static url', function() {
711+
$httpBackend.expect('GET', '/override-url?type=Customer&typeId=123').respond({id: 'abc'});
712+
var TypeItem = $resource('/:type/:typeId', {type: 'Order'}, {
713+
get: {
714+
method: 'GET',
715+
params: {type: 'Customer'},
716+
url: '/override-url'
717+
}
718+
});
719+
var item = TypeItem.get({typeId: 123});
720+
$httpBackend.flush();
721+
expect(item).toEqualData({id: 'abc'});
722+
});
723+
724+
725+
it('should support overriding url template with a new template ending in param', function() {
726+
// url parameter in action, parameter ending the string
727+
$httpBackend.expect('GET', '/Customer/123').respond({id: 'abc'});
728+
var TypeItem = $resource('/foo/:type', {type: 'Order'}, {
729+
get: {
730+
method: 'GET',
731+
params: {type: 'Customer'},
732+
url: '/:type/:typeId'
733+
}
734+
});
735+
var item = TypeItem.get({typeId: 123});
736+
$httpBackend.flush();
737+
expect(item).toEqualData({id: 'abc'});
738+
739+
// url parameter in action, parameter not ending the string
740+
$httpBackend.expect('GET', '/Customer/123/pay').respond({id: 'abc'});
741+
var TypeItem = $resource('/foo/:type', {type: 'Order'}, {
742+
get: {
743+
method: 'GET',
744+
params: {type: 'Customer'},
745+
url: '/:type/:typeId/pay'
746+
}
747+
});
748+
var item = TypeItem.get({typeId: 123});
749+
$httpBackend.flush();
750+
expect(item).toEqualData({id: 'abc'});
751+
});
752+
753+
754+
it('should support overriding url template with a new template ending in string', function() {
755+
$httpBackend.expect('GET', '/Customer/123/pay').respond({id: 'abc'});
756+
var TypeItem = $resource('/foo/:type', {type: 'Order'}, {
757+
get: {
758+
method: 'GET',
759+
params: {type: 'Customer'},
760+
url: '/:type/:typeId/pay'
761+
}
762+
});
763+
var item = TypeItem.get({typeId: 123});
764+
$httpBackend.flush();
765+
expect(item).toEqualData({id: 'abc'});
766+
});
767+
});
706768
});

0 commit comments

Comments
 (0)