Red
Red

Reputation: 7324

jQuery animation function breaks when switching tabs

UPDATE: I reproduced the error in a plunkr: See http://plnkr.co/BpYfCNBESUT6ZkiSZHgx

The problem occurs when you do following:

Open website. Refresh website, while you see the page is loading in the browser tab, when you see the spinner in the tab.

enter image description here
Switch to another tab in your browser. If it doens't happen. Try again. If did as said, you are most likely seeing this:

enter image description here

You might say, this is not such a big deal, you have to be real fast to let this error happen. However, imagine somebody with a slow connection, he goes to another tab in his browser, continue watching his youtube video, while website is loading. When he comes back he just sees the page keeps loading.


Lets say ive this animation code:

$pageloaderbar.animate({
    width: "46%"
}, {
    duration: 700,
    complete: function () {
        $scope.continue();
    }
});

When the first animation completes it calls an new function, called $scope.continue();. Which looks likes this:

$scope.continue = function () {
    $timeout(function () {
        $pageloaderbar.animate({
            width: "100%"
        }, {
            duration: 500,
            complete: function () {
                $scope.PageIsLoading = false;
            }
        });
    });
}

The problem is, when a user switches tab in his browser, between the $pageloaderbar.animate and the $scope.continue, the $plageloaderbar.animate function never reaches the complete function. The browser console shows the following error (Chrome)

enter image description here

My question is, how can i see if the user is active on the website? Or, how can i still execute the function, even if the user is not active on the browser tab?

Because there seems no one with an awnser, i have figured an little workaround myself. However, if someone still can explain why the animation breaks when switching tab, im very pleased.

The workaround was quite simple, i only had to add this code.

complete: function () {
    if(document.hidden) {
        $(window).on("blur focus", function () {
            $scope.continue();
        });
    } else {
        $scope.continue();
    }
}

instead of:

complete: function () {
    $scope.continue();
}

Upvotes: 1

Views: 1295

Answers (3)

Perran Mitchell
Perran Mitchell

Reputation: 1158

This is being caused by the jQuery animate function, which passes the animate options object to a function called speed. This function checks to see if the document is hidden - which it will be if the tab is inactive. If it is hidden, (or fx.off is set to true), all animation durations are set to 0.

You can see this on line 7137 in your plunkr's jQuery file.

    if ( jQuery.fx.off || document.hidden ) {
    opt.duration = 0;

As the animation now has no duration, it becomes synchronous, and so the fact that your complete function comes after the call to animate, is an issue.

To fix this, you would need to move the complete function declaration above your call to animate.

Upvotes: 4

A.Sri
A.Sri

Reputation: 311

In the newer version of chrome this is related to visibility of the tab and your function is breaking due to that. you can use visibility API to know that tab is visible to the user or not.

Please have a look at this link which i found :

http://dystroy.org/demos/vis-en.html

Upvotes: 0

arikanmstf
arikanmstf

Reputation: 473

 $scope.continue = function () {
        $timeout(function () {
            $pageloaderbar.animate({
                width: "100%"
            }, {
                duration: 500,
                complete: function () {
                    $scope.PageIsLoading = false;

                    $("body").css("overflow", "auto");
                    $pageloaderwrap.addClass("page-loader-finished");

                    $scope.pageReady();
                }
            });
        });
    }

    var $pageloaderwrap = $(".page-loader-wrap");
    var $pageloader = $(".page-loader");
    var $pageloaderbar = $(".page-loader .page-loader-bar");

    $("body").css("overflow", "hidden");


    $pageloaderbar.animate({
        width: "46%"
    }, {
        duration: 700,
        complete: function () {
            if (document.hidden) {
                $(window).on("blur focus", function () {
                    $scope.continue();
                });
            } else {
                $scope.continue();
            }
        }
    });

Try to define your continue function before call $pageloaderbar.animate . That may not be the main problem but, it is always possible to have a issue because of that.

Your solution is just a patch, not a real solution and not seems good. Even if it solves your problem, you must find a certain way to prevent this error.

I strongly recommend you to leave jquery. Such problems usually comes from jquery - angular incompatibilities.

Upvotes: -1

Related Questions