web-dev-qa-db-fra.com

Stop $ timeout lors du démarrage d'un nouveau contrôleur

J'interroge mes données toutes les 2 secondes pour les garder à jour sur la page. Mon problème est que lorsque je visite une autre page, le délai reste actif. Comment puis-je annuler mon délai d'expiration lorsque je visite une nouvelle page?

function IndexCtrl($scope, $timeout, RestData) {
    $scope.rd = {};

    (function getRestDataFromServer() {
        RestData.query(function(data){
            $scope.rd = data;
            $timeout(getRestDataFromServer, 2000);
        });
    })();
}

// EDIT J'ai trouvé une solution, mais je ne sais pas si elle est bonne. Lorsque j'enregistre mon délai d'expiration sur $ rootScope, je peux l'annuler dans tous les autres contrôleurs.

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); 
}
27
fraherm

Il y a quelques Angular qui sont diffusés lorsque l'itinéraire est modifié. Vous pouvez les écouter dans le IndexCtrl en utilisant $scope.$on Et agir en conséquence:

événement $ destroy

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() renvoie un objet promis. Cet objet peut être fourni à la fonction $timeout.cancel() pour annuler le délai d'attente.

64
Stewie

La réponse de Stewie est parfaite. Je voulais juste partager cette fonction d'aide simple que j'utilise au lieu d'utiliser directement $timeout, De sorte que je n'ai plus jamais à penser à ce problème:

function setTimeout(scope, fn, delay) {
    var promise = $timeout(fn, delay);
    var deregister = scope.$on('$destroy', function() {
        $timeout.cancel(promise);
    });
    promise.then(deregister, deregister);
}

J'ai ajouté cette fonction à un service appelé miscUtils, et j'injecte ce service au lieu d'injecter $timeout. Ensuite, par exemple, pour créer une fonction "mise à jour" qui s'exécute toutes les 30 secondes jusqu'à ce que $scope Soit détruit:

update();
function update() {
    // do the actual updating here
    miscUtils.setTimeout($scope, update, 30000);
}

Modifier pour ceux qui ne savent pas ce qui se passe avec deregister:

Cette fonction enregistre un écouteur pour l'événement $destroy, Mais une fois le délai d'attente terminé, il n'est plus nécessaire; il n'y a plus de délai d'expiration pour annuler. scope.$on renvoie une fonction qui, lorsqu'elle est appelée, désenregistre cet écouteur. Ainsi, promise.then(deregister) nettoie cet écouteur dont vous n'avez plus besoin dès que le délai est écoulé.

15
Eric Simonton