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

Commit 4493389

Browse files
Splaktarmmalerba
authored andcommitted
fix(input-container): handle initialization of md-icon with ng-if (#11437)
<!-- Filling out this template is required! Do not delete it when submitting a Pull Request! Without this information, your Pull Request may be auto-closed. --> ## PR Checklist Please check that your PR fulfills the following requirements: - [x] The commit message follows [our guidelines](https://github.com/angular/material/blob/master/.github/CONTRIBUTING.md#-commit-message-format) - [x] Tests for the changes have been added or this is not a bug fix / enhancement - [x] Docs have been added, updated, or were not required ## PR Type What kind of change does this PR introduce? <!-- Please check the one that applies to this PR using "x". --> ``` [x] Bugfix [ ] Enhancement [ ] Documentation content changes [ ] Code style update (formatting, local variables) [ ] Refactoring (no functional changes, no api changes) [ ] Build related changes [ ] CI related changes [ ] Infrastructure changes [ ] Other... Please describe: ``` ## What is the current behavior? If a `md-input-container` has an `md-icon` that has an `ng-if` that resolves to false (the icon should be removed), the `md-icon-left` or `md-icon-right` class is applied to the `md-input-container` incorrectly. This regression was introduced in 1.1.1. <!-- Please describe the current behavior that you are modifying and link to one or more relevant issues. --> Issue Number: Fixes #9529 Relates to #9155 Relates to #9151 ## What is the new behavior? If a `md-input-container` has an `md-icon` that has an `ng-if` that resolves to false (the icon should be removed), the `md-icon-left` or `md-icon-right` class won't be applied to the `md-input-container` incorrectly. ## Does this PR introduce a breaking change? ``` [ ] Yes [x] No ``` <!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. --> <!-- Note that breaking changes are highly unlikely to get merged to master unless the validation is clear and the use case is critical. --> ## Other information [This CodePen](https://codepen.io/Splaktar/pen/qMVxZB?editors=1010#0) demonstrates the fix in this PR.
1 parent dfba062 commit 4493389

File tree

2 files changed

+127
-15
lines changed

2 files changed

+127
-15
lines changed

src/components/input/input.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ if (window._mdMocksIncluded) {
9595
* </md-input-container>
9696
* </hljs>
9797
*/
98-
function mdInputContainerDirective($mdTheming, $parse) {
98+
function mdInputContainerDirective($mdTheming, $parse, $$rAF) {
9999

100100
var INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT', 'MD-SELECT'];
101101

@@ -115,15 +115,33 @@ function mdInputContainerDirective($mdTheming, $parse) {
115115

116116
function compile(tElement) {
117117
// Check for both a left & right icon
118-
var leftIcon = tElement[0].querySelector(LEFT_SELECTORS);
119-
var rightIcon = tElement[0].querySelector(RIGHT_SELECTORS);
120-
121-
if (leftIcon) { tElement.addClass('md-icon-left'); }
122-
if (rightIcon) { tElement.addClass('md-icon-right'); }
118+
var hasLeftIcon = tElement[0].querySelector(LEFT_SELECTORS);
119+
var hasRightIcon = tElement[0].querySelector(RIGHT_SELECTORS);
123120

124121
return function postLink(scope, element) {
125122
$mdTheming(element);
126-
};
123+
124+
if (hasLeftIcon || hasRightIcon) {
125+
// When accessing the element's contents synchronously, they may not be defined yet because
126+
// of the use of ng-if. If we wait one frame, then the element should be there if the ng-if
127+
// resolves to true.
128+
$$rAF(function() {
129+
// Handle the case where the md-icon element is initially hidden via ng-if from #9529.
130+
// We don't want to preserve the space for the icon in the case of ng-if, like we do for
131+
// ng-show.
132+
// Note that we can't use the same selectors from above because the elements are no longer
133+
// siblings for textareas at this point due to the insertion of the md-resize-wrapper.
134+
var iconNotRemoved = element[0].querySelector('md-icon') ||
135+
element[0].querySelector('.md-icon');
136+
if (hasLeftIcon && iconNotRemoved) {
137+
element.addClass('md-icon-left');
138+
}
139+
if (hasRightIcon && iconNotRemoved) {
140+
element.addClass('md-icon-right');
141+
}
142+
});
143+
}
144+
}
127145
}
128146

129147
function ContainerCtrl($scope, $element, $attrs, $animate) {

src/components/input/input.spec.js

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
describe('md-input-container directive', function() {
2-
var $rootScope, $compile, $timeout, pageScope;
2+
var $rootScope, $compile, $timeout, pageScope, $material;
33

44
var invalidAnimation, messagesAnimation, messageAnimation;
55
var $animProvider;
@@ -10,6 +10,7 @@ describe('md-input-container directive', function() {
1010
beforeEach(inject(function($injector) {
1111
$compile = $injector.get('$compile');
1212
$timeout = $injector.get('$timeout');
13+
$material = $injector.get('$material');
1314

1415
$rootScope = $injector.get('$rootScope');
1516
pageScope = $rootScope.$new();
@@ -981,9 +982,8 @@ describe('md-input-container directive', function() {
981982
' <input ng-model="foo">' +
982983
'</md-input-container>'
983984
);
984-
985+
$material.flushOutstandingAnimations();
985986
expect(el.hasClass('md-icon-left')).toBeTruthy();
986-
987987
});
988988

989989
it('should add md-icon-left class when .md-icon is before the input', function() {
@@ -993,6 +993,7 @@ describe('md-input-container directive', function() {
993993
' <input ng-model="foo">' +
994994
'</md-input-container>'
995995
);
996+
$material.flushOutstandingAnimations();
996997
expect(el.hasClass('md-icon-left')).toBeTruthy();
997998
});
998999

@@ -1003,7 +1004,7 @@ describe('md-input-container directive', function() {
10031004
' <md-icon></md-icon>' +
10041005
'</md-input-container>'
10051006
);
1006-
1007+
$material.flushOutstandingAnimations();
10071008
expect(el.hasClass('md-icon-right')).toBeTruthy();
10081009

10091010
});
@@ -1015,8 +1016,53 @@ describe('md-input-container directive', function() {
10151016
' <i class="md-icon"></i>' +
10161017
'</md-input-container>'
10171018
);
1019+
$material.flushOutstandingAnimations();
10181020
expect(el.hasClass('md-icon-right')).toBeTruthy();
10191021
});
1022+
it('should not add md-icon-left class when md-icon is before the input and ng-if="false"', function() {
1023+
var el = compile(
1024+
'<md-input-container>' +
1025+
' <md-icon ng-if="false"></md-icon>' +
1026+
' <input ng-model="foo">' +
1027+
'</md-input-container>'
1028+
);
1029+
$material.flushOutstandingAnimations();
1030+
expect(el.hasClass('md-icon-left')).toBeFalsy();
1031+
});
1032+
1033+
it('should not add md-icon-left class when .md-icon is before the input and ng-if="false"', function() {
1034+
var el = compile(
1035+
'<md-input-container>' +
1036+
' <i class="md-icon" ng-if="false"></i>' +
1037+
' <input ng-model="foo">' +
1038+
'</md-input-container>'
1039+
);
1040+
$material.flushOutstandingAnimations();
1041+
expect(el.hasClass('md-icon-left')).toBeFalsy();
1042+
});
1043+
1044+
it('should not add md-icon-right class when md-icon is after the input and ng-if="false"', function() {
1045+
var el = compile(
1046+
'<md-input-container>' +
1047+
' <input ng-model="foo">' +
1048+
' <md-icon ng-if="false"></md-icon>' +
1049+
'</md-input-container>'
1050+
);
1051+
$material.flushOutstandingAnimations();
1052+
expect(el.hasClass('md-icon-right')).toBeFalsy();
1053+
1054+
});
1055+
1056+
it('should not add md-icon-right class when .md-icon is after the input and ng-if="false"', function() {
1057+
var el = compile(
1058+
'<md-input-container>' +
1059+
' <input ng-model="foo">' +
1060+
' <i class="md-icon" ng-if="false"></i>' +
1061+
'</md-input-container>'
1062+
);
1063+
$material.flushOutstandingAnimations();
1064+
expect(el.hasClass('md-icon-right')).toBeFalsy();
1065+
});
10201066

10211067
it('should add md-icon-left and md-icon-right classes when md-icons are before and after the input', function() {
10221068
var el = compile(
@@ -1026,6 +1072,7 @@ describe('md-input-container directive', function() {
10261072
' <md-icon></md-icon>' +
10271073
'</md-input-container>'
10281074
);
1075+
$material.flushOutstandingAnimations();
10291076
expect(el.hasClass('md-icon-left md-icon-right')).toBeTruthy();
10301077
});
10311078

@@ -1037,17 +1084,42 @@ describe('md-input-container directive', function() {
10371084
' <i class="md-icon"></i>' +
10381085
'</md-input-container>'
10391086
);
1087+
$material.flushOutstandingAnimations();
10401088
expect(el.hasClass('md-icon-left md-icon-right')).toBeTruthy();
10411089
});
10421090

1091+
it('should not add md-icon-left and md-icon-right classes when md-icons are before and after the input and ng-if="false"', function() {
1092+
var el = compile(
1093+
'<md-input-container>' +
1094+
' <md-icon ng-if="false"></md-icon>' +
1095+
' <input ng-model="foo">' +
1096+
' <md-icon ng-if="false"></md-icon>' +
1097+
'</md-input-container>'
1098+
);
1099+
$material.flushOutstandingAnimations();
1100+
expect(el.hasClass('md-icon-left md-icon-right')).toBeFalsy();
1101+
});
1102+
1103+
it('should not add md-icon-left and md-icon-right classes when .md-icons are before and after the input and ng-if="false"', function() {
1104+
var el = compile(
1105+
'<md-input-container>' +
1106+
' <i class="md-icon" ng-if="false"></i>' +
1107+
' <input ng-model="foo">' +
1108+
' <i class="md-icon" ng-if="false"></i>' +
1109+
'</md-input-container>'
1110+
);
1111+
$material.flushOutstandingAnimations();
1112+
expect(el.hasClass('md-icon-left md-icon-right')).toBeFalsy();
1113+
});
1114+
10431115
it('should add md-icon-left class when md-icon is before select', function() {
10441116
var el = compile(
10451117
'<md-input-container>' +
10461118
' <md-icon></md-icon>' +
10471119
' <md-select ng-model="foo"></md-select>' +
10481120
'</md-input-container>'
10491121
);
1050-
1122+
$material.flushOutstandingAnimations();
10511123
expect(el.hasClass('md-icon-left')).toBeTruthy();
10521124
});
10531125

@@ -1058,7 +1130,7 @@ describe('md-input-container directive', function() {
10581130
' <md-icon></md-icon>' +
10591131
'</md-input-container>'
10601132
);
1061-
1133+
$material.flushOutstandingAnimations();
10621134
expect(el.hasClass('md-icon-right')).toBeTruthy();
10631135
});
10641136

@@ -1069,7 +1141,7 @@ describe('md-input-container directive', function() {
10691141
' <textarea ng-model="foo"></textarea>' +
10701142
'</md-input-container>'
10711143
);
1072-
1144+
$material.flushOutstandingAnimations();
10731145
expect(el.hasClass('md-icon-left')).toBeTruthy();
10741146
});
10751147

@@ -1080,9 +1152,31 @@ describe('md-input-container directive', function() {
10801152
' <md-icon></md-icon>' +
10811153
'</md-input-container>'
10821154
);
1083-
1155+
$material.flushOutstandingAnimations();
10841156
expect(el.hasClass('md-icon-right')).toBeTruthy();
10851157
});
1158+
1159+
it('should not add md-icon-left class when md-icon is before textarea and ng-if="false"', function() {
1160+
var el = compile(
1161+
'<md-input-container>' +
1162+
' <md-icon ng-if="false"></md-icon>' +
1163+
' <textarea ng-model="foo"></textarea>' +
1164+
'</md-input-container>'
1165+
);
1166+
$material.flushOutstandingAnimations();
1167+
expect(el.hasClass('md-icon-left')).toBeFalsy();
1168+
});
1169+
1170+
it('should not add md-icon-right class when md-icon is before textarea and ng-if="false"', function() {
1171+
var el = compile(
1172+
'<md-input-container>' +
1173+
' <textarea ng-model="foo"></textarea>' +
1174+
' <md-icon ng-if="false"></md-icon>' +
1175+
'</md-input-container>'
1176+
);
1177+
$material.flushOutstandingAnimations();
1178+
expect(el.hasClass('md-icon-right')).toBeFalsy();
1179+
});
10861180
});
10871181
});
10881182
});

0 commit comments

Comments
 (0)