Reputation: 691
I'm polling for my data every 2 seconds to keep them updated on the page. My problem is when I visit another page the timeout stays active. How can i cancel my timeout when I visit an new page?
function IndexCtrl($scope, $timeout, RestData) {
$scope.rd = {};
(function getRestDataFromServer() {
RestData.query(function(data){
$scope.rd = data;
$timeout(getRestDataFromServer, 2000);
});
})();
}
//EDIT I found a solution, but I'm not sure if it's a good one. When i save my timeout to the $rootScope, I can cancel it in all the other controllers.
function IndexCtrl($scope, $rootScope, $timeout, RestData) {
$scope.rd = {};
(function getRestDataFromServer() {
RestData.query(function(data){
$scope.rd = data;
$rootScope.prom = $timeout(getRestDataFromServer, 2000);
});
})();
}
function newPageCtrl($scope, $rootScope, $timeout) {
$timeout.cancel($rootScope.prom);
}
Upvotes: 27
Views: 25925
Reputation: 6029
Stewie's answer is perfect. I just wanted to share this simple helper function that I use instead of using $timeout
directly, so that I never have to think about this issue again:
function setTimeout(scope, fn, delay) {
var promise = $timeout(fn, delay);
var deregister = scope.$on('$destroy', function() {
$timeout.cancel(promise);
});
promise.then(deregister, deregister);
}
I added this function to a service called miscUtils
, and I inject that service instead of injecting $timeout
. Then, for example, to make an "update" function that runs every 30 seconds until $scope
is destroyed:
update();
function update() {
// do the actual updating here
miscUtils.setTimeout($scope, update, 30000);
}
Edit for those confused about what's going on with deregister
:
This function registers a listener for the $destroy
event, but once the timeout has completed it is no longer necessary; there is no longer a timeout to cancel. scope.$on
returns a function that, when called, deregisters that listener. So, promise.then(deregister)
cleans up that no-longer-needed listener as soon as the timeout completes.
Upvotes: 15
Reputation: 60406
There are couple of Angular events that are being broadcasted when route is being changed. You can listen for them within the IndexCtrl
using $scope.$on
and act accordingly:
$destroy event
var promise = $timeout(getRestDataFromServer, 2000);
...
$scope.$on('$destroy', function(){
$timeout.cancel(promise);
});
$locationChangeStart
var promise = $timeout(getRestDataFromServer, 2000);
...
$scope.$on('$locationChangeStart', function(){
$timeout.cancel(promise);
});
$timeout()
returns a promise object. This object can be supplied to $timeout.cancel()
function to cancel the timeout.
Upvotes: 65