AngularJS cancels all pending $ http requests when changing a route

Please read the code first

app.js

var app = angular.module('Nimbus', ['ngRoute']); 

route.js

 app.config(function($routeProvider) { $routeProvider .when('/login', { controller: 'LoginController', templateUrl: 'templates/pages/login.html', title: 'Login' }) .when('/home', { controller: 'HomeController', templateUrl: 'templates/pages/home.html', title: 'Dashboard' }) .when('/stats', { controller: 'StatsController', templateUrl: 'templates/pages/stats.html', title: 'Stats' }) }).run( function($q, $rootScope, $location, $route, Auth) { $rootScope.$on( "$routeChangeStart", function(event, next, current) { console.log("Started"); /* this line not working */ var canceler = $q.defer(); canceler.resolve(); }); $rootScope.$on("$routeChangeSuccess", function(currentRoute, previousRoute){ $rootScope.title = ($route.current.title) ? $route.current.title : 'Welcome'; }); }) 

homeowners controller.js

 app.controller('HomeController', function HomeController($scope, API) { API.all(function(response){ console.log(response); }) } ) 

statistics-controller.js

 app.controller('StatsController', function StatsController($scope, API) { API.all(function(response){ console.log(response); }) } ) 

api.js

 app.factory('API', ['$q','$http', function($q, $http) { return { all: function(callback) { var canceler = $q.defer(); var apiurl = 'some_url' $http.get(apiurl,{timeout: canceler.promise}).success(callback); } } }]); 

When I go from home to statistics, again the API will send an http request, I have many such HTTP requests, I have pasted only a few lines of code.

I need to have cancel cancel all pending http requests for routechangestart or success

Or any other way to implement the same?

+43
javascript angularjs
Apr 23 '14 at 12:32
source share
4 answers

I put together a concept code for this. You may need to customize to suit your needs. There is a pendingRequests service that has an API for adding, receiving and canceling requests, httpService , which wraps $http and ensures that all requests are tracked.

Using the configuration object $http ( docs ), we can get a way to cancel the pending request.

I did plnkr, but you will need quick fingers to see how requests are canceled, since the test site I found usually responds within half a second, but you will see on the network tab devtools that the requests do cancel. In your case, you obviously trigger the cancelAll() call on the corresponding events from $routeProvider .

The controller should just demonstrate the concept.

Demo

 angular.module('app', []) // This service keeps track of pending requests .service('pendingRequests', function() { var pending = []; this.get = function() { return pending; }; this.add = function(request) { pending.push(request); }; this.remove = function(request) { pending = _.filter(pending, function(p) { return p.url !== request; }); }; this.cancelAll = function() { angular.forEach(pending, function(p) { p.canceller.resolve(); }); pending.length = 0; }; }) // This service wraps $http to make sure pending requests are tracked .service('httpService', ['$http', '$q', 'pendingRequests', function($http, $q, pendingRequests) { this.get = function(url) { var canceller = $q.defer(); pendingRequests.add({ url: url, canceller: canceller }); //Request gets cancelled if the timeout-promise is resolved var requestPromise = $http.get(url, { timeout: canceller.promise }); //Once a request has failed or succeeded, remove it from the pending list requestPromise.finally(function() { pendingRequests.remove(url); }); return requestPromise; } }]) // The controller just helps generate requests and keep a visual track of pending ones .controller('AppCtrl', ['$scope', 'httpService', 'pendingRequests', function($scope, httpService, pendingRequests) { $scope.requests = []; $scope.$watch(function() { return pendingRequests.get(); }, function(pending) { $scope.requests = pending; }) var counter = 1; $scope.addRequests = function() { for (var i = 0, l = 9; i < l; i++) { httpService.get('https://public.opencpu.org/ocpu/library/?foo=' + counter++); } }; $scope.cancelAll = function() { pendingRequests.cancelAll(); } }]); 
+53
Aug 28 '14 at 6:24
source

You can use $http.pendingRequests for this.

First, when you make a request, do the following:

 var cancel = $q.defer(); var request = { method: method, url: requestUrl, data: data, timeout: cancel.promise, // cancel promise, standard thing in $http request cancel: cancel // this is where we do our magic }; $http(request).then(.....); 

Now we will cancel all our pending requests in $routeChangeStart

 $rootScope.$on('$routeChangeStart', function (event, next, current) { $http.pendingRequests.forEach(function(request) { if (request.cancel) { request.cancel.resolve(); } }); }); 

This way you can also “protect” a particular request from cancellation by simply not submitting a “cancel” request in the request.

+9
May 30 '16 at 10:41
source

I think this is the best solution to cancel requests. It uses the intercept event and $ routeChangeSuccess. http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/

+6
Jul 07 '15 at 16:12
source

Please note that im new with Angular, so this may not be optimal. Another solution might be: in a $ http request with the addition of the argument "timeout", Docs I did this as follows:

In the factory where I call all Rest services, use this logic.

 module.factory('myactory', ['$http', '$q', function ($http, $q) { var canceler = $q.defer(); var urlBase = '/api/blabla'; var factory = {}; factory.CANCEL_REQUESTS = function () { canceler.resolve(); this.ENABLE_REQUESTS(); }; factory.ENABLE_REQUESTS = function () { canceler = $q.defer(); }; factory.myMethod = function () { return $http.get(urlBase, {timeout: canceler.promise}); }; factory.myOtherMethod= function () { return $http.post(urlBase, {a:a, b:b}, {timeout: canceler.promise}); }; return factory; }]); 

and in the Angular application configuration I have:

 return angular.module('app', ['ngRoute', 'ngSanitize', 'app.controllers', 'app.factories', 'app.filters', 'app.directives', 'ui.bootstrap', 'ngGeolocation', 'ui.select' ]) .run(['$location', '$rootScope', 'myFactory', function($location, $rootScope, myFactory) { $rootScope.$on('$routeChangeSuccess', function (event, current, previous) { myFactory.CANCEL_REQUESTS(); $rootScope.title = current.$$route.title; }); }]); 

Thus, it captures all changes to the “route” and stops the entire request configured with this “timer” so that you can choose what is important to you.

I hope this helps someone. Relations

0
Apr 23 '15 at 0:41
source



All Articles