Спрете $timeout при стартиране на нов контролер

Търся данните си на всеки 2 секунди, за да ги поддържам актуализирани на страницата. Проблемът ми е, че когато посетя друга страница, времето за изчакване остава активно. Как мога да отменя времето за изчакване, когато посетя нова страница?

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

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

//РЕДАКТИРАНЕ Намерих решение, но не съм сигурен дали е добро. Когато запазя времето си за изчакване в $rootScope, мога да го отменя във всички останали контролери.

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

person fraherm    schedule 16.06.2013    source източник
comment
пробвахте ли $timeout.cancel()?   -  person Ivan Chernykh    schedule 16.06.2013


Отговори (2)


Има няколко Angular събития, които се излъчват, когато маршрутът се променя. Можете да ги слушате в рамките на IndexCtrl с помощта на $scope.$on и да действате съответно:

$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() връща обещаващ обект. Този обект може да бъде предоставен на функцията $timeout.cancel() за отмяна на времето за изчакване.

person Stewie    schedule 17.06.2013
comment
Благодаря! Точно това търсех. =) - person fraherm; 17.06.2013
comment
Всъщност това е $timeout.cancel(promise). - person David Bennett; 11.07.2013

Отговорът на Стюи е перфектен. Просто исках да споделя тази проста помощна функция, която използвам вместо да използвам $timeout директно, така че никога повече да не мисля за този проблем:

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

Добавих тази функция към услуга, наречена miscUtils, и инжектирам тази услуга, вместо да инжектирам $timeout. След това, например, за да направите функция за "актуализация", която да се изпълнява на всеки 30 секунди, докато $scope бъде унищожено:

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

Редактиране за тези, които са объркани какво се случва с deregister:

Тази функция регистрира слушател за събитието $destroy, но след като времето за изчакване приключи, вече не е необходимо; вече няма таймаут за анулиране. scope.$on връща функция, която при извикване дерегистрира това слушател. И така, promise.then(deregister) почиства този вече ненужен слушател веднага щом времето за изчакване изтече.

person Eric Simonton    schedule 13.06.2014
comment
Това звучи като много добро решение. Бихте ли споделили целия код, като работещ пример, включително дефиницията на услугата, така че за мен като начинаещ е по-лесно да го интегрирам в собственото си приложение? Благодаря ти! - person SHernandez; 24.06.2014
comment
Променливата deregister ме обърка за известно време, мислех, че е функцията за отмяна на времето за изчакване, но не е така. Това е функцията за отмяна на анулирането на таймаут. - person dshepherd; 22.03.2016
comment
@dshepherd, моля, обяснете, защото все още съм объркан. - person natanavra; 27.09.2016
comment
Ако променливата беше наречена deregisterDestroyListener, това може да помогне? - person dshepherd; 28.09.2016