diff --git a/README.md b/README.md index 5ea6dc25..740f7688 100644 --- a/README.md +++ b/README.md @@ -988,6 +988,30 @@ Create custom methods for your models using Restangular.extendModel(). This is a }); ``` +## Adding Custom Methods to Services + +Create custom methods for a particular service: +```js +app.factory("User", ["Restangular", function(Restangular) { + var User = Restangular.service("users"); + User.paginate = function(page) { + return this.getList({page: page}); + } + return User; +}]); +``` + +Add custom methods for all services: +```js +app.config(["RestangularProvider", function(RestangularProvider) { + RestangularProvider.extendServices({ + paginate: function(page) { + return this.getList({page: page}); + } + }); +}]); +``` + # FAQ #### **How can I handle errors?** diff --git a/src/restangular.js b/src/restangular.js index 493a1f47..618c1f3e 100644 --- a/src/restangular.js +++ b/src/restangular.js @@ -446,6 +446,12 @@ module.provider('Restangular', function() { return object.addElementTransformer(route, false, fn); }; + config.serviceMixin = config.serviceMixin || {}; + object.extendServices = function(newMixin) { + config.serviceMixin = _.extend(config.serviceMixin, newMixin); + return this; + } + config.transformElem = function(elem, isCollection, route, Restangular, force) { if (!force && !config.transformLocalElements && !elem[config.restangularFields.fromServer]) { return elem; @@ -1265,7 +1271,7 @@ module.provider('Restangular', function() { } function toService(route, parent) { - var serv = {}; + var serv = _.extend({}, config.serviceMixin); var collection = (parent || service).all(route); serv.one = _.bind(one, (parent || service), parent, route); serv.post = _.bind(collection.post, collection); diff --git a/test/restangularSpec.js b/test/restangularSpec.js index 6dcad6ba..3f73b0de 100644 --- a/test/restangularSpec.js +++ b/test/restangularSpec.js @@ -41,6 +41,7 @@ describe("Restangular", function() { $httpBackend.when("OPTIONS", "/accounts").respond(); $httpBackend.whenGET("/accounts").respond(accountsModel); + $httpBackend.whenGET("/accounts?page=4").respond(accountsModel); $httpBackend.whenJSONP("/accounts").respond(accountsModel); $httpBackend.whenGET("/accounts/0,1").respond(accountsModel); $httpBackend.whenGET("/accounts/messages").respond(messages); @@ -218,7 +219,7 @@ describe("Restangular", function() { $httpBackend.flush(); }); - + }); describe("Local data", function() { @@ -245,7 +246,7 @@ describe("Restangular", function() { $httpBackend.flush(); - expect(obj.amount).toEqual(3.1416); + expect(obj.amount).toEqual(3.1416); }); it("Shouldn't be restangularized by default", function() { @@ -356,9 +357,9 @@ describe("Restangular", function() { it("Doing a post and then other operation (delete) should call right URLs", function() { restangularAccounts.post(newAccount).then(function(added) { added.remove(); - $httpBackend.expectDELETE('/accounts/44').respond(201, ''); - }); - + $httpBackend.expectDELETE('/accounts/44').respond(201, ''); + }); + $httpBackend.flush(); }); @@ -445,6 +446,22 @@ describe("Restangular", function() { $httpBackend.flush(); }); + it("should allow extend services", function() { + var childRestangular = Restangular.withConfig(function(config) { + config.extendServices({ + paginate: function(page) { + return this.getList({ page: page }); + } + }); + }); + + var Accounts = childRestangular.service("accounts"); + Accounts.paginate(4); + + $httpBackend.expectGET('/accounts?page=4'); + $httpBackend.flush(); + }); + }); describe("ONE", function() { @@ -471,7 +488,7 @@ describe("Restangular", function() { $httpBackend.expectPOST('/accounts/1'); account1.name = "Hey"; account1.save(); - + $httpBackend.flush(); }); @@ -510,7 +527,7 @@ describe("Restangular", function() { newAc.remove(); $httpBackend.expectDELETE("/accounts/1"); }); - $httpBackend.expectPUT("/accounts/1"); + $httpBackend.expectPUT("/accounts/1"); }); @@ -576,7 +593,7 @@ describe("Restangular", function() { }); accountsPromise = Restangular.all('accounts').getList(); - + accountsPromise.then(function(accounts) { expect(typeof accounts.totalAmount).toEqual("function"); }); @@ -586,14 +603,14 @@ describe("Restangular", function() { it("should allow for a custom method to be placed at the model level when one model is requested", function() { var accountPromise; - + Restangular.addElementTransformer('accounts', false, function(model) { model.prettifyAmount = function() {}; return model; }); accountPromise = Restangular.one('accounts', 1).get(); - + accountPromise.then(function(account) { expect(typeof account.prettifyAmount).toEqual("function"); }); @@ -603,14 +620,14 @@ describe("Restangular", function() { it("should allow for a custom method to be placed at the model level when several models are requested", function() { var accountPromise; - + Restangular.addElementTransformer('accounts', false, function(model) { model.prettifyAmount = function() {}; return model; }); accountsPromise = Restangular.all('accounts', 1).getList(); - + accountsPromise.then(function(accounts) { accounts.forEach(function(account, index) { expect(typeof account.prettifyAmount).toEqual("function"); @@ -650,47 +667,47 @@ describe("Restangular", function() { expect(spy).toHaveBeenCalledWith('accounts', false, fn); }); }); - + describe("defaultHeaders", function() { it("should return defaultHeaders", function() { var defaultHeaders = {testheader:'header value'}; - + Restangular.setDefaultHeaders(defaultHeaders); - + expect(Restangular.defaultHeaders).toEqual(defaultHeaders); }); }); - + describe("defaultRequestParams", function() { it("should return defaultRequestParams", function() { var defaultRequestParams = {param:'value'}; - + Restangular.setDefaultRequestParams(defaultRequestParams); - + expect(Restangular.requestParams.common).toEqual(defaultRequestParams); }); - + it("should be able to set default params for get, post, put.. methods separately", function() { var postParams = {post:'value'}, putParams = {put:'value'}; - + Restangular.setDefaultRequestParams('post', postParams); expect(Restangular.requestParams.post).toEqual(postParams); - + Restangular.setDefaultRequestParams('put', putParams); expect(Restangular.requestParams.put).toEqual(putParams); - + expect(Restangular.requestParams.common).not.toEqual(putParams); }); - + it("should be able to set default params for multiple methods with array", function() { var defaultParams = {param:'value'}; - + Restangular.setDefaultRequestParams(['post', 'put'], defaultParams); - + expect(Restangular.requestParams.post).toEqual(defaultParams); expect(Restangular.requestParams.put).toEqual(defaultParams); - + expect(Restangular.requestParams.common).not.toEqual(defaultParams); }); }); @@ -703,14 +720,14 @@ describe("Restangular", function() { expect(Restangular.configuration.baseUrl).toEqual(''); expect(childRestangular.configuration.baseUrl).toEqual('/api/v1'); - + }); it("should allow nested configurations", function() { var childRestangular = Restangular.withConfig(function(RestangularConfigurer){ RestangularConfigurer.setBaseUrl('/api/v1'); }); - + var grandchildRestangular = childRestangular.withConfig(function(RestangularConfigurer){ RestangularConfigurer.setRequestSuffix('.json'); });