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

Commit ce5f7c2

Browse files
topherfangiokara
authored andcommitted
fix(autocomplete): fix messages not appearing. (#9909)
Fixes #9468.
1 parent 454b974 commit ce5f7c2

File tree

3 files changed

+142
-14
lines changed

3 files changed

+142
-14
lines changed

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

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

@@ -98,6 +98,93 @@ describe('md-input-container animations', function() {
9898
expect(lastAnimateCall.options.to).toEqual({"opacity": 1, "margin-top": "0"});
9999
});
100100

101+
describe('method tests', function() {
102+
103+
describe('#showInputMessages', function() {
104+
it('logs a warning with no messages element', inject(function($log) {
105+
// Note that the element does NOT have a parent md-input-messages-animation class
106+
var element = angular.element('<div><div class="md-input-message-animation"></div></div>');
107+
var done = jasmine.createSpy('done');
108+
var warnSpy = spyOn($log, 'warn');
109+
110+
$$mdInput.messages.show(element, done);
111+
112+
expect(done).toHaveBeenCalled();
113+
expect(warnSpy).toHaveBeenCalled();
114+
}));
115+
116+
it('logs a warning with no messages children', inject(function($log) {
117+
// Note that the element does NOT have any child md-input-message-animation divs
118+
var element = angular.element('<div class="md-input-messages-animation"></div>');
119+
var done = jasmine.createSpy('done');
120+
var warnSpy = spyOn($log, 'warn');
121+
122+
$$mdInput.messages.show(element, done);
123+
124+
expect(done).toHaveBeenCalled();
125+
expect(warnSpy).toHaveBeenCalled();
126+
}));
127+
});
128+
129+
describe('#hideInputMessages', function() {
130+
it('logs a warning with no messages element', inject(function($log) {
131+
// Note that the element does NOT have a parent md-input-messages-animation class
132+
var element = angular.element('<div><div class="md-input-message-animation"></div></div>');
133+
var done = jasmine.createSpy('done');
134+
var warnSpy = spyOn($log, 'warn');
135+
136+
$$mdInput.messages.hide(element, done);
137+
138+
expect(done).toHaveBeenCalled();
139+
expect(warnSpy).toHaveBeenCalled();
140+
}));
141+
142+
it('logs a warning with no messages children', inject(function($log) {
143+
// Note that the element does NOT have any child md-input-message-animation divs
144+
var element = angular.element('<div class="md-input-messages-animation"></div>');
145+
var done = jasmine.createSpy('done');
146+
var warnSpy = spyOn($log, 'warn');
147+
148+
$$mdInput.messages.hide(element, done);
149+
150+
expect(done).toHaveBeenCalled();
151+
expect(warnSpy).toHaveBeenCalled();
152+
}));
153+
});
154+
155+
describe('#getMessagesElement', function() {
156+
157+
it('finds the messages element itself', function() {
158+
var template = '<div class="md-input-messages-animation"></div>';
159+
var dom = angular.element(template);
160+
var messages = $$mdInput.messages.getElement(dom);
161+
162+
expect(dom).toEqual(messages);
163+
});
164+
165+
it('finds a child element', function(){
166+
var template = '<div><div class="md-input-messages-animation"></div></div>';
167+
var dom = angular.element(template);
168+
var realMessages = angular.element(dom[0].querySelector('.md-input-messages-animation'));
169+
var messages = $$mdInput.messages.getElement(dom);
170+
171+
expect(realMessages).toEqual(messages);
172+
});
173+
174+
it('finds the parent of a message animation element', function() {
175+
var template =
176+
'<div class="md-input-messages-animation">' +
177+
' <div class="md-input-message-animation"></div>' +
178+
'</div>';
179+
var dom = angular.element(template);
180+
var message = angular.element(dom[0].querySelector('.md-input-message-animation'));
181+
var messages = $$mdInput.messages.getElement(message);
182+
183+
expect(dom).toEqual(messages);
184+
});
185+
});
186+
});
187+
101188
/*
102189
* Test Helper Functions
103190
*/
@@ -168,8 +255,9 @@ describe('md-input-container animations', function() {
168255
$compile = $injector.get('$compile');
169256
$animateCss = $injector.get('$animateCss');
170257
$material = $injector.get('$material');
258+
$$mdInput = $injector.get('$$mdInput');
171259

172-
// Grab our input animations
260+
// Grab our input animations (we MUST use the injector to setup dependencies)
173261
invalidAnimation = $injector.get('mdInputInvalidAnimation');
174262
messagesAnimation = $injector.get('mdInputMessagesAnimation');
175263
messageAnimation = $injector.get('mdInputMessageAnimation');

src/components/input/input.js

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @ngdoc module
33
* @name material.components.input
44
*/
5-
angular.module('material.components.input', [
5+
var inputModule = angular.module('material.components.input', [
66
'material.core'
77
])
88
.directive('mdInputContainer', mdInputContainerDirective)
@@ -18,12 +18,26 @@ angular.module('material.components.input', [
1818

1919
.animation('.md-input-invalid', mdInputInvalidMessagesAnimation)
2020
.animation('.md-input-messages-animation', ngMessagesAnimation)
21-
.animation('.md-input-message-animation', ngMessageAnimation)
21+
.animation('.md-input-message-animation', ngMessageAnimation);
22+
23+
// If we are running inside of tests; expose some extra services so that we can test them
24+
if (window._mdMocksIncluded) {
25+
inputModule.service('$$mdInput', function() {
26+
return {
27+
// special accessor to internals... useful for testing
28+
messages: {
29+
show : showInputMessages,
30+
hide : hideInputMessages,
31+
getElement : getMessagesElement
32+
}
33+
}
34+
})
2235

2336
// Register a service for each animation so that we can easily inject them into unit tests
2437
.service('mdInputInvalidAnimation', mdInputInvalidMessagesAnimation)
2538
.service('mdInputMessagesAnimation', ngMessagesAnimation)
2639
.service('mdInputMessageAnimation', ngMessageAnimation);
40+
}
2741

2842
/**
2943
* @ngdoc directive
@@ -890,10 +904,10 @@ function ngMessageDirective($mdUtil) {
890904
}
891905
}
892906

893-
var $$AnimateRunner, $animateCss, $mdUtil;
907+
var $$AnimateRunner, $animateCss, $mdUtil, $log;
894908

895-
function mdInputInvalidMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil) {
896-
saveSharedServices($$AnimateRunner, $animateCss, $mdUtil);
909+
function mdInputInvalidMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil, $log) {
910+
saveSharedServices($$AnimateRunner, $animateCss, $mdUtil, $log);
897911

898912
return {
899913
addClass: function(element, className, done) {
@@ -904,8 +918,8 @@ function mdInputInvalidMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil)
904918
};
905919
}
906920

907-
function ngMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil) {
908-
saveSharedServices($$AnimateRunner, $animateCss, $mdUtil);
921+
function ngMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil, $log) {
922+
saveSharedServices($$AnimateRunner, $animateCss, $mdUtil, $log);
909923

910924
return {
911925
enter: function(element, done) {
@@ -934,8 +948,8 @@ function ngMessagesAnimation($$AnimateRunner, $animateCss, $mdUtil) {
934948
};
935949
}
936950

937-
function ngMessageAnimation($$AnimateRunner, $animateCss, $mdUtil) {
938-
saveSharedServices($$AnimateRunner, $animateCss, $mdUtil);
951+
function ngMessageAnimation($$AnimateRunner, $animateCss, $mdUtil, $log) {
952+
saveSharedServices($$AnimateRunner, $animateCss, $mdUtil, $log);
939953

940954
return {
941955
enter: function(element, done) {
@@ -955,8 +969,15 @@ function ngMessageAnimation($$AnimateRunner, $animateCss, $mdUtil) {
955969
function showInputMessages(element, done) {
956970
var animators = [], animator;
957971
var messages = getMessagesElement(element);
972+
var children = messages.children();
973+
974+
if (messages.length == 0 || children.length == 0) {
975+
$log.warn('mdInput messages show animation called on invalid messages element: ', element);
976+
done();
977+
return;
978+
}
958979

959-
angular.forEach(messages.children(), function(child) {
980+
angular.forEach(children, function(child) {
960981
animator = showMessage(angular.element(child));
961982

962983
animators.push(animator.start());
@@ -968,8 +989,15 @@ function showInputMessages(element, done) {
968989
function hideInputMessages(element, done) {
969990
var animators = [], animator;
970991
var messages = getMessagesElement(element);
992+
var children = messages.children();
971993

972-
angular.forEach(messages.children(), function(child) {
994+
if (messages.length == 0 || children.length == 0) {
995+
$log.warn('mdInput messages hide animation called on invalid messages element: ', element);
996+
done();
997+
return;
998+
}
999+
1000+
angular.forEach(children, function(child) {
9731001
animator = hideMessage(angular.element(child));
9741002

9751003
animators.push(animator.start());
@@ -1028,6 +1056,11 @@ function getInputElement(element) {
10281056
}
10291057

10301058
function getMessagesElement(element) {
1059+
// If we ARE the messages element, just return ourself
1060+
if (element.hasClass('md-input-messages-animation')) {
1061+
return element;
1062+
}
1063+
10311064
// If we are a ng-message element, we need to traverse up the DOM tree
10321065
if (element.hasClass('md-input-message-animation')) {
10331066
return angular.element($mdUtil.getClosest(element, function(node) {
@@ -1039,8 +1072,9 @@ function getMessagesElement(element) {
10391072
return angular.element(element[0].querySelector('.md-input-messages-animation'));
10401073
}
10411074

1042-
function saveSharedServices(_$$AnimateRunner_, _$animateCss_, _$mdUtil_) {
1075+
function saveSharedServices(_$$AnimateRunner_, _$animateCss_, _$mdUtil_, _$log_) {
10431076
$$AnimateRunner = _$$AnimateRunner_;
10441077
$animateCss = _$animateCss_;
10451078
$mdUtil = _$mdUtil_;
1079+
$log = _$log_;
10461080
}

test/angular-material-mocks.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616

1717
'use strict';
1818

19+
// Allow our code to know when they are running inside of a test so they can expose extra services
20+
// that should NOT be exposed to the public but that should be tested.
21+
//
22+
// As an example, see input.js which exposes some animation-related methods.
23+
window._mdMocksIncluded = true;
24+
1925
/**
2026
* @ngdoc module
2127
* @name ngMaterial-mock

0 commit comments

Comments
 (0)