Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 4e302c2

Browse files
topherfangiohansl
authored andcommitted
fix(input): Ensure animated messages disappear. (#9466)
After some recent changes to the input animations, the input could get into a state where animated messages were still being shown even if they were invalid. The underlying issue was that the animation was not calling the `done` function and Angular's animation framework was thus not actually removing the element from the DOM, so any further message animations found the old message in the DOM and attempted to show it. - Ensure all input animations properly call the `.done()` method which is returned by `$animateCss()`. - Update tests to check for `.done()` calls and use a better method for flushing the animations. - Remove some old/commented code. Fixes #9454.
1 parent d086e2b commit 4e302c2

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

src/components/input/input-animations.spec.js

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
describe('md-input-container animations', function() {
2-
var $rootScope, $compile, $animate, $animateCss,
2+
var $rootScope, $compile, $animateCss, $material,
33
el, pageScope, invalidAnimation, messagesAnimation, messageAnimation,
44
cssTransitionsDisabled = false, lastAnimateCall;
55

@@ -28,7 +28,8 @@ describe('md-input-container animations', function() {
2828
);
2929

3030
var container = el.find('md-input-container'),
31-
input = el.find('input');
31+
input = el.find('input'),
32+
doneSpy = jasmine.createSpy('done');
3233

3334
// Mimic the real validations/animations that fire
3435

@@ -39,10 +40,11 @@ describe('md-input-container animations', function() {
3940
*/
4041

4142
setFoo('asdf');
42-
messageAnimation.enter(getError()).start().done(angular.noop);
43-
$animate.flush();
43+
messageAnimation.enter(getError(), doneSpy);
44+
flush();
4445

4546
expectError(getError(), 'pattern');
47+
expect(doneSpy).toHaveBeenCalled();
4648
expect(container).not.toHaveClass('md-input-invalid');
4749
expect(lastAnimateCall).toEqual({element: getError(), options: {}});
4850

@@ -52,11 +54,13 @@ describe('md-input-container animations', function() {
5254
* Expect to animate in the pattern message
5355
*/
5456

57+
doneSpy.calls.reset();
5558
input.triggerHandler('blur');
56-
invalidAnimation.addClass(container, 'md-input-invalid', angular.noop);
57-
$animate.flush();
59+
invalidAnimation.addClass(container, 'md-input-invalid', doneSpy);
60+
flush();
5861

5962
expectError(getError(), 'pattern');
63+
expect(doneSpy).toHaveBeenCalled();
6064
expect(container).toHaveClass('md-input-invalid');
6165
expect(lastAnimateCall.element).toEqual(getError());
6266
expect(lastAnimateCall.options.event).toEqual('enter');
@@ -71,19 +75,23 @@ describe('md-input-container animations', function() {
7175
// Grab the pattern error before we change foo and it disappears
7276
var patternError = getError();
7377

74-
messageAnimation.leave(patternError).start().done(angular.noop);
75-
$animate.flush();
78+
doneSpy.calls.reset();
79+
messageAnimation.leave(patternError, doneSpy);
80+
flush();
7681

82+
expect(doneSpy).toHaveBeenCalled();
7783
expect(lastAnimateCall.element).toEqual(patternError);
7884
expect(lastAnimateCall.options.event).toEqual('leave');
7985
expect(parseInt(lastAnimateCall.options.to["margin-top"])).toBeLessThan(0);
8086

8187
setFoo('');
8288
expectError(getError(), 'required');
8389

84-
messageAnimation.enter(getError()).start().done(angular.noop);
85-
$animate.flush();
90+
doneSpy.calls.reset();
91+
messageAnimation.enter(getError(), doneSpy);
92+
flush();
8693

94+
expect(doneSpy).toHaveBeenCalled();
8795
expect(container).toHaveClass('md-input-invalid');
8896
expect(lastAnimateCall.element).toEqual(getError());
8997
expect(lastAnimateCall.options.event).toEqual('enter');
@@ -116,6 +124,12 @@ describe('md-input-container animations', function() {
116124
expect(element.text().trim()).toBe(message);
117125
}
118126

127+
function flush() {
128+
// Note: we use flushInterimElement() because it actually calls everything 3 times which seems
129+
// to be enough to actually flush the animations
130+
$material.flushInterimElement();
131+
}
132+
119133
/*
120134
* before/afterEach Helper Functions
121135
*/
@@ -152,8 +166,8 @@ describe('md-input-container animations', function() {
152166
inject(function($injector) {
153167
$rootScope = $injector.get('$rootScope');
154168
$compile = $injector.get('$compile');
155-
$animate = $injector.get('$animate');
156169
$animateCss = $injector.get('$animateCss');
170+
$material = $injector.get('$material');
157171

158172
// Grab our input animations
159173
invalidAnimation = $injector.get('mdInputInvalidAnimation');

src/components/input/input.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -936,11 +936,15 @@ function ngMessageAnimation($$AnimateRunner, $animateCss, $mdUtil) {
936936

937937
return {
938938
enter: function(element, done) {
939-
return showMessage(element);
939+
var animator = showMessage(element);
940+
941+
animator.start().done(done);
940942
},
941943

942944
leave: function(element, done) {
943-
return hideMessage(element);
945+
var animator = hideMessage(element);
946+
947+
animator.start().done(done);
944948
}
945949
}
946950
}
@@ -998,7 +1002,6 @@ function showMessage(element) {
9981002
function hideMessage(element) {
9991003
var height = element[0].offsetHeight;
10001004
var styles = window.getComputedStyle(element[0]);
1001-
//var styles = { opacity: element.css('opacity') };
10021005

10031006
// If we are already hidden, just return an empty animation
10041007
if (styles.opacity == 0) {

0 commit comments

Comments
 (0)