diff --git a/src/lib/input/input.spec.ts b/src/lib/input/input.spec.ts index 72b8c5e3aba..43304897295 100644 --- a/src/lib/input/input.spec.ts +++ b/src/lib/input/input.spec.ts @@ -5,7 +5,15 @@ import { wrappedErrorMessage, MockNgZone, } from '@angular/cdk/testing'; -import {ChangeDetectionStrategy, Component, ViewChild, Type, Provider, NgZone} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ViewChild, + Type, + Provider, + NgZone, + Directive, +} from '@angular/core'; import {ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing'; import { FormControl, @@ -35,8 +43,7 @@ import {By} from '@angular/platform-browser'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {MatStepperModule} from '@angular/material/stepper'; import {MatTabsModule} from '@angular/material/tabs'; -import {MatInputModule} from './index'; -import {MatInput} from './input'; +import {MatInputModule, MatInput, MAT_INPUT_VALUE_ACCESSOR} from './index'; import {MatTextareaAutosize} from './autosize'; describe('MatInput without forms', () => { @@ -889,6 +896,20 @@ describe('MatInput without forms', () => { expect(formField.classList).not.toContain('mat-form-field-type-mat-native-select'); }); + it('should use the native input value when determining whether ' + + 'the element is empty with a custom accessor', fakeAsync(() => { + let fixture = createComponent(MatInputWithCustomAccessor, [], [], [CustomMatInputAccessor]); + fixture.detectChanges(); + let label = fixture.debugElement.query(By.css('label')).nativeElement; + + expect(label.classList).toContain('mat-form-field-empty'); + + fixture.nativeElement.querySelector('input').value = 'abc'; + fixture.detectChanges(); + + expect(label.classList).not.toContain('mat-form-field-empty'); + })); + }); describe('MatInput with forms', () => { @@ -1368,7 +1389,8 @@ describe('MatInput with textarea autosize', () => { function createComponent(component: Type, providers: Provider[] = [], - imports: any[] = []): ComponentFixture { + imports: any[] = [], + declarations: any[] = []): ComponentFixture { TestBed.configureTestingModule({ imports: [ FormsModule, @@ -1379,7 +1401,7 @@ function createComponent(component: Type, ReactiveFormsModule, ...imports ], - declarations: [component], + declarations: [component, ...declarations], providers, }).compileComponents(); @@ -1876,3 +1898,26 @@ class MatInputSelectWithLabel {} ` }) class MatInputSelectWithInnerHtml {} + +@Component({ + template: ` + + + ` +}) +class MatInputWithCustomAccessor {} + + +/** Custom component that never has a value. Used for testing the `MAT_INPUT_VALUE_ACCESSOR`. */ +@Directive({ + selector: 'input[customInputAccessor]', + providers: [{ + provide: MAT_INPUT_VALUE_ACCESSOR, + useExisting: CustomMatInputAccessor + }] +}) +class CustomMatInputAccessor { + get value() { return this._value; } + set value(_value: any) {} + private _value = null; +} diff --git a/src/lib/input/input.ts b/src/lib/input/input.ts index 59835fafbbc..df26d845cc7 100644 --- a/src/lib/input/input.ts +++ b/src/lib/input/input.ts @@ -332,7 +332,7 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl< /** Does some manual dirty checking on the native input `value` property. */ protected _dirtyCheckNativeValue() { - const newValue = this.value; + const newValue = this._elementRef.nativeElement.value; if (this._previousNativeValue !== newValue) { this._previousNativeValue = newValue;