From 37d1e5e399b5fbd63f57333cbbe31b97aeae18f8 Mon Sep 17 00:00:00 2001 From: Artemy Tregubenko Date: Fri, 3 Jan 2014 13:06:30 +0100 Subject: [PATCH 1/3] feat(ngResource): Add $abort method to objects returned by $resource "class" actions --- src/ngResource/resource.js | 15 ++++++++++++++- test/ngResource/resourceSpec.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js index 8874bbeca484..e61e2223e7eb 100644 --- a/src/ngResource/resource.js +++ b/src/ngResource/resource.js @@ -202,6 +202,8 @@ function shallowClearAndCopy(src, dst) { * rejection), `false` before that. Knowing if the Resource has been resolved is useful in * data-binding. * + * - `$abort`: a method to abort the request if it has not completed yet. + * * @example * * # Credit card resource @@ -303,7 +305,7 @@ function shallowClearAndCopy(src, dst) { * */ angular.module('ngResource', ['ng']). - factory('$resource', ['$http', '$q', function($http, $q) { + factory('$resource', ['$http', '$q', '$timeout', function($http, $q, $timeout) { var DEFAULT_ACTIONS = { 'get': {method:'GET'}, @@ -501,6 +503,16 @@ angular.module('ngResource', ['ng']). } }); + // If parameters do not contain `timeout` which is a promise, create it, + // so that later this call can be aborted by resolving this promise + var timeout = httpConfig.timeout; + if (!timeout || !timeout.then) { + var timeoutDeferred = $q.defer(); + httpConfig.timeout = timeoutDeferred.promise; + // If timeout is specified in milliseconds, use it to abort via promise + if (timeout) $timeout(timeoutDeferred.resolve, timeout); + } + if (hasBody) httpConfig.data = data; route.setUrlParams(httpConfig, extend({}, extractParams(data, action.params || {}), params), @@ -557,6 +569,7 @@ angular.module('ngResource', ['ng']). // - return the instance / collection value.$promise = promise; value.$resolved = false; + if (timeoutDeferred) value.$abort = timeoutDeferred.resolve; return value; } diff --git a/test/ngResource/resourceSpec.js b/test/ngResource/resourceSpec.js index b23f0ca42bd7..c0fe645fad0a 100644 --- a/test/ngResource/resourceSpec.js +++ b/test/ngResource/resourceSpec.js @@ -674,6 +674,22 @@ describe("resource", function() { }); + it('should add $abort method to the result object', function(){ + $httpBackend.expect('POST', '/CreditCard/123!charge?amount=10', '{"auth":"abc"}').respond({success: 'ok'}); + var errorCallback = jasmine.createSpy(); + var cc = CreditCard.charge({id:123, amount:10}, {auth:'abc'}); + cc.$promise.then(callback, errorCallback); + + expect(cc.$abort).toEqual(jasmine.any(Function)); + cc.$abort(); + + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + expect(callback).not.toHaveBeenCalled(); + expect(errorCallback).toHaveBeenCalled(); + }); + + it('should return promise from action method calls', function() { $httpBackend.expect('GET', '/CreditCard/123').respond({id: 123, number: '9876'}); var cc = new CreditCard({name: 'Mojo'}); @@ -837,6 +853,22 @@ describe("resource", function() { expect(callback).toHaveBeenCalledOnce(); expect(ccs.$resolved).toBe(true); }); + + + it('should add $abort method to the result object', function(){ + $httpBackend.expect('GET', '/CreditCard?key=value').respond([{id: 1}, {id: 2}]); + var errorCallback = jasmine.createSpy(); + var ccs = CreditCard.query({key: 'value'}); + ccs.$promise.then(callback, errorCallback); + + expect(ccs.$abort).toEqual(jasmine.any(Function)); + ccs.$abort(); + + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + expect(callback).not.toHaveBeenCalled(); + expect(errorCallback).toHaveBeenCalled(); + }); }); it('should allow per action response interceptor that gets full response', function() { From b8472b5422cae4eec52f1b4063b11816d1edba59 Mon Sep 17 00:00:00 2001 From: Artemy Tregubenko Date: Fri, 3 Jan 2014 13:06:30 +0100 Subject: [PATCH 2/3] feat(ngResource): Add $abort method to objects returned by $resource "class" actions `$resource` "class" actions delegate to `$http` in a fashion that does not allow to pass timeout promise to individual requests. Hence these individual requests can not be cancelled. This patch adds $abort method to the object returned by `$resource` "class" actions. Closes #5612 --- src/ngResource/resource.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js index e61e2223e7eb..51c093702a39 100644 --- a/src/ngResource/resource.js +++ b/src/ngResource/resource.js @@ -506,8 +506,9 @@ angular.module('ngResource', ['ng']). // If parameters do not contain `timeout` which is a promise, create it, // so that later this call can be aborted by resolving this promise var timeout = httpConfig.timeout; + var timeoutDeferred; if (!timeout || !timeout.then) { - var timeoutDeferred = $q.defer(); + timeoutDeferred = $q.defer(); httpConfig.timeout = timeoutDeferred.promise; // If timeout is specified in milliseconds, use it to abort via promise if (timeout) $timeout(timeoutDeferred.resolve, timeout); From 117bca0f926416ed5d7fcad69b9dcdef005009af Mon Sep 17 00:00:00 2001 From: Artemy Tregubenko Date: Fri, 3 Jan 2014 14:22:04 +0100 Subject: [PATCH 3/3] updated commit author to atregoubenko@gmail.com --- src/ngResource/resource.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js index 51c093702a39..79281954dd1c 100644 --- a/src/ngResource/resource.js +++ b/src/ngResource/resource.js @@ -504,7 +504,7 @@ angular.module('ngResource', ['ng']). }); // If parameters do not contain `timeout` which is a promise, create it, - // so that later this call can be aborted by resolving this promise + // so that later this call can be aborted by resolving this promise. var timeout = httpConfig.timeout; var timeoutDeferred; if (!timeout || !timeout.then) {