fix(form-field): always use native input value to determine whether control is empty (#13307)

Currently we use the input value accessor to figure out whether an input has a value. This doesn't handle the case with `matDatepicker` where we have a custom accessor whose model value may not change, even though the value in the input has changed. These changes switch to always using the value from the input element.

Fixes #13305.
This commit is contained in:
Kristiyan Kostadinov
2018-09-27 16:11:00 +02:00
committed by Jeremy Elbourn
parent 845388cdaa
commit 10e6502147
2 changed files with 51 additions and 6 deletions
+50 -5
View File
@@ -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<T>(component: Type<T>,
providers: Provider[] = [],
imports: any[] = []): ComponentFixture<T> {
imports: any[] = [],
declarations: any[] = []): ComponentFixture<T> {
TestBed.configureTestingModule({
imports: [
FormsModule,
@@ -1379,7 +1401,7 @@ function createComponent<T>(component: Type<T>,
ReactiveFormsModule,
...imports
],
declarations: [component],
declarations: [component, ...declarations],
providers,
}).compileComponents();
@@ -1876,3 +1898,26 @@ class MatInputSelectWithLabel {}
</mat-form-field>`
})
class MatInputSelectWithInnerHtml {}
@Component({
template: `
<mat-form-field floatLabel="never">
<input matInput customInputAccessor placeholder="Placeholder">
</mat-form-field>`
})
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;
}
+1 -1
View File
@@ -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;