Skip to content

Commit

Permalink
fix(autocomplete): placeholder not resetting properly (#6141)
Browse files Browse the repository at this point in the history
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"`.
  • Loading branch information
crisbeto authored and tinayuangao committed Aug 2, 2017
1 parent a780052 commit e4e7ee9
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 6 deletions.
11 changes: 10 additions & 1 deletion src/lib/autocomplete/autocomplete-trigger.ts
Expand Up @@ -409,9 +409,18 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {

private _setTriggerValue(value: any): void {
const toDisplay = this.autocomplete.displayWith ? this.autocomplete.displayWith(value) : value;

// Simply falling back to an empty string if the display value is falsy does not work properly.
// The display value can also be the number zero and shouldn't fall back to an empty string.
this._element.nativeElement.value = toDisplay != null ? toDisplay : '';
const inputValue = toDisplay != null ? toDisplay : '';

// If it's used in a Material container, we should set it through
// the property so it can go through the change detection.
if (this._inputContainer) {
this._inputContainer._mdInputChild.value = inputValue;
} else {
this._element.nativeElement.value = inputValue;
}
}

/**
Expand Down
36 changes: 33 additions & 3 deletions src/lib/autocomplete/autocomplete.spec.ts
Expand Up @@ -54,7 +54,8 @@ describe('MdAutocomplete', () => {
AutocompleteWithNumbers,
AutocompleteWithOnPushDelay,
AutocompleteWithNativeInput,
AutocompleteWithoutPanel
AutocompleteWithoutPanel,
AutocompleteWithFormsAndNonfloatingPlaceholder
],
providers: [
{provide: OverlayContainer, useFactory: () => {
Expand Down Expand Up @@ -1314,6 +1315,21 @@ describe('MdAutocomplete', () => {
}).toThrow(getMdAutocompleteMissingPanelError());
}));

it('should hide the placeholder with a preselected form control value ' +
'and a disabled floating placeholder', fakeAsync(() => {
const fixture = TestBed.createComponent(AutocompleteWithFormsAndNonfloatingPlaceholder);

fixture.detectChanges();
tick();
fixture.detectChanges();

const input = fixture.nativeElement.querySelector('input');
const placeholder = fixture.nativeElement.querySelector('.mat-input-placeholder');

expect(input.value).toBe('California');
expect(placeholder.classList).not.toContain('mat-empty');
}));

});

it('should have correct width when opened', () => {
Expand Down Expand Up @@ -1501,7 +1517,6 @@ class AutocompleteWithoutForms {
onInput(value: any) {
this.filteredStates = this.states.filter(s => new RegExp(value, 'gi').test(s));
}

}


Expand Down Expand Up @@ -1531,7 +1546,6 @@ class AutocompleteWithNgModel {
onInput(value: any) {
this.filteredStates = this.states.filter(s => new RegExp(value, 'gi').test(s));
}

}

@Component({
Expand Down Expand Up @@ -1611,3 +1625,19 @@ class AutocompleteWithNativeInput {
class AutocompleteWithoutPanel {
@ViewChild(MdAutocompleteTrigger) trigger: MdAutocompleteTrigger;
}


@Component({
template: `
<md-input-container floatPlaceholder="never">
<input placeholder="State" mdInput [mdAutocomplete]="auto" [formControl]="formControl">
</md-input-container>
<md-autocomplete #auto="mdAutocomplete">
<md-option value="California">California</md-option>
</md-autocomplete>
`
})
class AutocompleteWithFormsAndNonfloatingPlaceholder {
formControl = new FormControl('California');
}
19 changes: 19 additions & 0 deletions src/lib/input/input-container.spec.ts
Expand Up @@ -566,6 +566,25 @@ describe('MdInputContainer without forms', function () {
expect(labelEl.classList).not.toContain('mat-float');
});

it('should be able to toggle the floating placeholder programmatically', () => {
const fixture = TestBed.createComponent(MdInputContainerWithId);

fixture.detectChanges();

const inputContainer = fixture.debugElement.query(By.directive(MdInputContainer));
const containerInstance = inputContainer.componentInstance as MdInputContainer;
const placeholder = inputContainer.nativeElement.querySelector('.mat-input-placeholder');

expect(containerInstance.floatPlaceholder).toBe('auto');
expect(placeholder.classList).toContain('mat-empty', 'Expected input to be considered empty.');

containerInstance.floatPlaceholder = 'always';
fixture.detectChanges();

expect(placeholder.classList)
.not.toContain('mat-empty', 'Expected input to be considered not empty.');
});

it('should not have prefix and suffix elements when none are specified', () => {
let fixture = TestBed.createComponent(MdInputContainerWithId);
fixture.detectChanges();
Expand Down
12 changes: 10 additions & 2 deletions src/lib/input/input-container.ts
Expand Up @@ -207,7 +207,12 @@ export class MdInputDirective implements OnChanges, OnDestroy, DoCheck {

/** The input element's value. */
get value() { return this._elementRef.nativeElement.value; }
set value(value: string) { this._elementRef.nativeElement.value = value; }
set value(value: string) {
if (value !== this.value) {
this._elementRef.nativeElement.value = value;
this._stateChanges.next();
}
}

/** Whether the input is empty. */
get empty() {
Expand Down Expand Up @@ -443,7 +448,10 @@ export class MdInputContainer implements AfterViewInit, AfterContentInit, AfterC
@Input()
get floatPlaceholder() { return this._floatPlaceholder; }
set floatPlaceholder(value: FloatPlaceholderType) {
this._floatPlaceholder = value || this._placeholderOptions.float || 'auto';
if (value !== this._floatPlaceholder) {
this._floatPlaceholder = value || this._placeholderOptions.float || 'auto';
this._changeDetectorRef.markForCheck();
}
}
private _floatPlaceholder: FloatPlaceholderType;

Expand Down

0 comments on commit e4e7ee9

Please sign in to comment.