Skip to content

Commit e4e7ee9

Browse files
crisbetotinayuangao
authored andcommitted
fix(autocomplete): placeholder not resetting properly (#6141)
Fixes the following regressions that were introduced by the switch to OnPush change detection: * The floating placeholder not resetting when the user closes the panel without selecting a value. * The placeholder overlapping the input value when the autocomplete has a preselected value and `floatPlaceholder="never"`.
1 parent a780052 commit e4e7ee9

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,18 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
409409

410410
private _setTriggerValue(value: any): void {
411411
const toDisplay = this.autocomplete.displayWith ? this.autocomplete.displayWith(value) : value;
412+
412413
// Simply falling back to an empty string if the display value is falsy does not work properly.
413414
// The display value can also be the number zero and shouldn't fall back to an empty string.
414-
this._element.nativeElement.value = toDisplay != null ? toDisplay : '';
415+
const inputValue = toDisplay != null ? toDisplay : '';
416+
417+
// If it's used in a Material container, we should set it through
418+
// the property so it can go through the change detection.
419+
if (this._inputContainer) {
420+
this._inputContainer._mdInputChild.value = inputValue;
421+
} else {
422+
this._element.nativeElement.value = inputValue;
423+
}
415424
}
416425

417426
/**

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ describe('MdAutocomplete', () => {
5454
AutocompleteWithNumbers,
5555
AutocompleteWithOnPushDelay,
5656
AutocompleteWithNativeInput,
57-
AutocompleteWithoutPanel
57+
AutocompleteWithoutPanel,
58+
AutocompleteWithFormsAndNonfloatingPlaceholder
5859
],
5960
providers: [
6061
{provide: OverlayContainer, useFactory: () => {
@@ -1314,6 +1315,21 @@ describe('MdAutocomplete', () => {
13141315
}).toThrow(getMdAutocompleteMissingPanelError());
13151316
}));
13161317

1318+
it('should hide the placeholder with a preselected form control value ' +
1319+
'and a disabled floating placeholder', fakeAsync(() => {
1320+
const fixture = TestBed.createComponent(AutocompleteWithFormsAndNonfloatingPlaceholder);
1321+
1322+
fixture.detectChanges();
1323+
tick();
1324+
fixture.detectChanges();
1325+
1326+
const input = fixture.nativeElement.querySelector('input');
1327+
const placeholder = fixture.nativeElement.querySelector('.mat-input-placeholder');
1328+
1329+
expect(input.value).toBe('California');
1330+
expect(placeholder.classList).not.toContain('mat-empty');
1331+
}));
1332+
13171333
});
13181334

13191335
it('should have correct width when opened', () => {
@@ -1501,7 +1517,6 @@ class AutocompleteWithoutForms {
15011517
onInput(value: any) {
15021518
this.filteredStates = this.states.filter(s => new RegExp(value, 'gi').test(s));
15031519
}
1504-
15051520
}
15061521

15071522

@@ -1531,7 +1546,6 @@ class AutocompleteWithNgModel {
15311546
onInput(value: any) {
15321547
this.filteredStates = this.states.filter(s => new RegExp(value, 'gi').test(s));
15331548
}
1534-
15351549
}
15361550

15371551
@Component({
@@ -1611,3 +1625,19 @@ class AutocompleteWithNativeInput {
16111625
class AutocompleteWithoutPanel {
16121626
@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
16131627
}
1628+
1629+
1630+
@Component({
1631+
template: `
1632+
<md-input-container floatPlaceholder="never">
1633+
<input placeholder="State" mdInput [mdAutocomplete]="auto" [formControl]="formControl">
1634+
</md-input-container>
1635+
1636+
<md-autocomplete #auto="mdAutocomplete">
1637+
<md-option value="California">California</md-option>
1638+
</md-autocomplete>
1639+
`
1640+
})
1641+
class AutocompleteWithFormsAndNonfloatingPlaceholder {
1642+
formControl = new FormControl('California');
1643+
}

src/lib/input/input-container.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,25 @@ describe('MdInputContainer without forms', function () {
566566
expect(labelEl.classList).not.toContain('mat-float');
567567
});
568568

569+
it('should be able to toggle the floating placeholder programmatically', () => {
570+
const fixture = TestBed.createComponent(MdInputContainerWithId);
571+
572+
fixture.detectChanges();
573+
574+
const inputContainer = fixture.debugElement.query(By.directive(MdInputContainer));
575+
const containerInstance = inputContainer.componentInstance as MdInputContainer;
576+
const placeholder = inputContainer.nativeElement.querySelector('.mat-input-placeholder');
577+
578+
expect(containerInstance.floatPlaceholder).toBe('auto');
579+
expect(placeholder.classList).toContain('mat-empty', 'Expected input to be considered empty.');
580+
581+
containerInstance.floatPlaceholder = 'always';
582+
fixture.detectChanges();
583+
584+
expect(placeholder.classList)
585+
.not.toContain('mat-empty', 'Expected input to be considered not empty.');
586+
});
587+
569588
it('should not have prefix and suffix elements when none are specified', () => {
570589
let fixture = TestBed.createComponent(MdInputContainerWithId);
571590
fixture.detectChanges();

src/lib/input/input-container.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,12 @@ export class MdInputDirective implements OnChanges, OnDestroy, DoCheck {
207207

208208
/** The input element's value. */
209209
get value() { return this._elementRef.nativeElement.value; }
210-
set value(value: string) { this._elementRef.nativeElement.value = value; }
210+
set value(value: string) {
211+
if (value !== this.value) {
212+
this._elementRef.nativeElement.value = value;
213+
this._stateChanges.next();
214+
}
215+
}
211216

212217
/** Whether the input is empty. */
213218
get empty() {
@@ -443,7 +448,10 @@ export class MdInputContainer implements AfterViewInit, AfterContentInit, AfterC
443448
@Input()
444449
get floatPlaceholder() { return this._floatPlaceholder; }
445450
set floatPlaceholder(value: FloatPlaceholderType) {
446-
this._floatPlaceholder = value || this._placeholderOptions.float || 'auto';
451+
if (value !== this._floatPlaceholder) {
452+
this._floatPlaceholder = value || this._placeholderOptions.float || 'auto';
453+
this._changeDetectorRef.markForCheck();
454+
}
447455
}
448456
private _floatPlaceholder: FloatPlaceholderType;
449457

0 commit comments

Comments
 (0)