From 547357a3e7efeef8fd58cf3234fd155ac11884e7 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Mon, 28 Nov 2022 17:30:04 +0100 Subject: [PATCH] fix(material/form-field): not visually disabled if form control is disabled without emitting an event (#26088) Fixes that the form field wasn't visually disabled if the consumer disables it using `emitEvents: false`. Fixes #26057. --- src/material/input/input.spec.ts | 16 ++++++++++++++-- src/material/input/input.ts | 12 +++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/material/input/input.spec.ts b/src/material/input/input.spec.ts index e4ef498b3dc8..ab31bfc1e3f7 100644 --- a/src/material/input/input.spec.ts +++ b/src/material/input/input.spec.ts @@ -1188,7 +1188,7 @@ describe('MatMdcInput with forms', () => { describe('custom error behavior', () => { it('should display an error message when a custom error matcher returns true', fakeAsync(() => { - let fixture = createComponent(MatInputWithCustomErrorStateMatcher); + let fixture = createComponent(InputInFormGroup); fixture.detectChanges(); let component = fixture.componentInstance; @@ -1356,6 +1356,18 @@ describe('MatMdcInput with forms', () => { expect(notch.style.width).toBeTruthy(); })); + + it('should mark the form field as disabled when a group is disabled with emitEvent: false', fakeAsync(() => { + const fixture = createComponent(InputInFormGroup); + fixture.detectChanges(); + + const mdcTextField = fixture.nativeElement.querySelector('.mdc-text-field'); + expect(mdcTextField.classList).not.toContain('mdc-text-field--disabled'); + + fixture.componentInstance.formGroup.disable({emitEvent: false}); + fixture.detectChanges(); + expect(mdcTextField.classList).toContain('mdc-text-field--disabled'); + })); }); describe('MatFormField default options', () => { @@ -1793,7 +1805,7 @@ class MatInputWithFormErrorMessages { `, }) -class MatInputWithCustomErrorStateMatcher { +class InputInFormGroup { formGroup = new FormGroup({ name: new FormControl('', [Validators.required, Validators.pattern(/valid value/)]), }); diff --git a/src/material/input/input.ts b/src/material/input/input.ts index 1332900981be..a4e1b6f998e4 100644 --- a/src/material/input/input.ts +++ b/src/material/input/input.ts @@ -160,9 +160,6 @@ export class MatInput */ @Input() get disabled(): boolean { - if (this.ngControl && this.ngControl.disabled !== null) { - return this.ngControl.disabled; - } return this._disabled; } set disabled(value: BooleanInput) { @@ -356,6 +353,15 @@ export class MatInput // error triggers that we can't subscribe to (e.g. parent form submissions). This means // that whatever logic is in here has to be super lean or we risk destroying the performance. this.updateErrorState(); + + // Since the input isn't a `ControlValueAccessor`, we don't have a good way of knowing when + // the disabled state has changed. We can't use the `ngControl.statusChanges`, because it + // won't fire if the input is disabled with `emitEvents = false`, despite the input becoming + // disabled. + if (this.ngControl.disabled !== null && this.ngControl.disabled !== this.disabled) { + this.disabled = this.ngControl.disabled; + this.stateChanges.next(); + } } // We need to dirty-check the native element's value, because there are some cases where