Giovanni
Giovanni

Reputation: 425

Ionic: $timeout action is being executed even if it is cancelled

Good afternoon,

I've been struggling with an unfamiliar problem. But first let me explain what I'm trying to achieve.

Purpose

What I'm trying to do is, setting a timer on each view, so if the internet connection is slow the timer calls a function which displays an ionicPopup with the question: "Would you like to refresh the view?" combined with a refresh button. When the button is clicked, the view will refresh. If the view loads in time (I've set the timer on 10000 milliseconds), the $timeout.cancel action is being called and the timer stops.

If that would be all it would be working fine at the moment.

Problem

If I navigate through my main pages rapidly, it looks like the timers aren't stop and the "Refresh popup" pops up on another page. That only happens when you click through at high speed. It looks like a few popup pop up at once beneath each other. I don't know what might be the problem, but I guess that the $timeout.cancel isn't being called if you navigate through the pages to quickly.

Code

Service

    .factory('Timer', function ($ionicPopup, $state, $timeout) {
    return {
        start: start
    };

    function start() {
        return $timeout(showPopup, 10000);
    }

    function showPopup() {
        $ionicPopup.show({
            title: 'Slow internetconnection',
            template: 'Click refresh to try again.',
            buttons: [
                {
                    text: 'Refresh',
                    onTap: function (e) {
                        $state.reload()
                    }
                }
            ]
        })
    }
})

Controller

    .controller('HomeCtrl', function ($scope, Request, Timer, $timeout) {
    var timer = Timer.start();

    Request.execute().finally(function () {
        $timeout.cancel(timer);
    })

    $scope.$on('$destroy', function () {
        $timeout.cancel(timer);
    });
})

I hope my problem is understandable.

Upvotes: 0

Views: 202

Answers (1)

mani
mani

Reputation: 3096

The key thing to note here is:

If I navigate through my main pages rapidly, it looks like the timers aren't stop and the "Refresh popup" pops up on another page.

As you navigate through, your ionic views are created/destroyed, and therefore you lose references to timer objects.

So, in controllers where you are using timers, you must invalidate the timer before you leave that page. This is because timers are wrappers around JavaScript's setTimeout and setInterval, and JavaScript has method level scope that passes the method as a parameter to setInterval which will hold a reference to it, while your controller gets destroyed. Therefore, when you change view, although your controller instance may get removed, the timer does not.

Add $ionicView.afterLeave callbacks in your controllers.

$scope.$on("$ionicView.afterLeave", function(event, data){
   $timeout.cancel(timer);
});

This will cancel the timer for a particular controller, after that controller's view is dismissed.

Upvotes: 3

Related Questions