fix(ngAnimate): do not trigger animations if the document is hidden

Prior to this fix, ngAnimate would always trigger animations even if
the browser tab or browser window was not visible. This would cause
issues with class updates / DOM operations even if elements were not
using animations. The root cause is that browsers do not flush calls to
requestAnimationFrame when browser windows / tabs are not visible.

This fix disables animations if `document.hidden` is `true`.

Closes #12842
Closes #13776
This commit is contained in:
Matias Niemelä
2016-01-15 09:16:08 -08:00
committed by Martin Staffa
parent 20bc37fbc8
commit a3a7afd3aa
2 changed files with 28 additions and 1 deletions
+3 -1
View File
@@ -337,7 +337,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
// this is a hard disable of all animations for the application or on
// the element itself, therefore there is no need to continue further
// past this point if not enabled
var skipAnimations = !animationsEnabled || disabledElementsLookup.get(node);
// Animations are also disabled if the document is currently hidden (page is not visible
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
var skipAnimations = !animationsEnabled || $document[0].hidden || disabledElementsLookup.get(node);
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
var hasExistingAnimation = !!existingAnimation.state;
+25
View File
@@ -148,6 +148,31 @@ describe("animations", function() {
expect(copiedOptions).toEqual(initialOptions);
}));
it("should skip animations entirely if the document is hidden", function() {
var doc;
module(function($provide) {
doc = jqLite({
body: document.body,
hidden: true
});
$provide.value('$document', doc);
});
inject(function($animate, $rootScope) {
$animate.enter(element, parent);
$rootScope.$digest();
expect(capturedAnimation).toBeFalsy();
expect(element[0].parentNode).toEqual(parent[0]);
doc[0].hidden = false;
$animate.leave(element);
$rootScope.$digest();
expect(capturedAnimation).toBeTruthy();
});
});
it('should animate only the specified CSS className matched within $animateProvider.classNameFilter', function() {
module(function($animateProvider) {
$animateProvider.classNameFilter(/only-allow-this-animation/);