fix($animate): ensure hidden elements with ngShow/ngHide stay hidden during animations

Prior to this fix if an element that contained ng-show or ng-hide was in its hidden state
then any other animation run on the same element would cause the animation to appear despite
the element itself already being hidden. This patch ensures that NO animations are visible
even if the element is set as hidden.

Closes #9103
Closes #9493
This commit is contained in:
Matias Niemelä
2014-10-08 14:36:33 +03:00
committed by Igor Minar
parent 035ffb82c4
commit 39d0b36826
3 changed files with 55 additions and 3 deletions

View File

@@ -2,7 +2,7 @@
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak,
.ng-hide:not(.ng-animate) {
.ng-hide:not(.ng-hide-animate) {
display: none !important;
}

View File

@@ -1,5 +1,7 @@
'use strict';
var NG_HIDE_CLASS = 'ng-hide';
var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
/**
* @ngdoc directive
* @name ngShow
@@ -161,7 +163,11 @@ var ngShowDirective = ['$animate', function($animate) {
multiElement: true,
link: function(scope, element, attr) {
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
$animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide');
// we're adding a temporary, animation-specific class for ng-hide since this way
// we can control when the element is actually displayed on screen without having
// to have a global/greedy CSS selector that breaks when other animations are run.
// Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
$animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
});
}
};
@@ -316,7 +322,9 @@ var ngHideDirective = ['$animate', function($animate) {
multiElement: true,
link: function(scope, element, attr) {
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
$animate[value ? 'addClass' : 'removeClass'](element, 'ng-hide');
// The comment inside of the ngShowDirective explains why we add and
// remove a temporary class for the show/hide animation
$animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
});
}
};

View File

@@ -156,6 +156,28 @@ describe('ngShow / ngHide animations', function() {
expect(item.element.text()).toBe('data');
expect(item.element).toBeHidden();
}));
it('should apply the temporary `.ng-hide-animate` class to the element',
inject(function($compile, $rootScope, $animate) {
var item;
var $scope = $rootScope.$new();
$scope.on = false;
element = $compile(html(
'<div class="show-hide" ng-show="on">data</div>'
))($scope);
$scope.$digest();
item = $animate.queue.shift();
expect(item.event).toEqual('addClass');
expect(item.options).toEqual('ng-hide-animate');
$scope.on = true;
$scope.$digest();
item = $animate.queue.shift();
expect(item.event).toEqual('removeClass');
expect(item.options).toEqual('ng-hide-animate');
}));
});
describe('ngHide', function() {
@@ -181,5 +203,27 @@ describe('ngShow / ngHide animations', function() {
expect(item.element.text()).toBe('datum');
expect(item.element).toBeShown();
}));
it('should apply the temporary `.ng-hide-animate` class to the element',
inject(function($compile, $rootScope, $animate) {
var item;
var $scope = $rootScope.$new();
$scope.on = false;
element = $compile(html(
'<div class="show-hide" ng-hide="on">data</div>'
))($scope);
$scope.$digest();
item = $animate.queue.shift();
expect(item.event).toEqual('removeClass');
expect(item.options).toEqual('ng-hide-animate');
$scope.on = true;
$scope.$digest();
item = $animate.queue.shift();
expect(item.event).toEqual('addClass');
expect(item.options).toEqual('ng-hide-animate');
}));
});
});