From ef20461b5a4d10066448bd53b139de615776375b Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 7 Jan 2021 15:15:32 +0200 Subject: [PATCH] fix(material/select): disabled state out of sync when swapping form group with a disabled one Fixes the disabled state of a `mat-select` falling out of sync with its form control if the control's group is swapped out with one that is disabled on init. Fixes #17860. --- .../mdc-select/select.spec.ts | 43 +++++++++++++++++++ src/material/select/select.spec.ts | 42 ++++++++++++++++++ src/material/select/select.ts | 5 +++ 3 files changed, 90 insertions(+) diff --git a/src/material-experimental/mdc-select/select.spec.ts b/src/material-experimental/mdc-select/select.spec.ts index 5763e2328b43..940978fba049 100644 --- a/src/material-experimental/mdc-select/select.spec.ts +++ b/src/material-experimental/mdc-select/select.spec.ts @@ -42,6 +42,7 @@ import { } from '@angular/core/testing'; import { ControlValueAccessor, + FormBuilder, FormControl, FormGroup, FormGroupDirective, @@ -130,6 +131,7 @@ describe('MDC-based MatSelect', () => { SelectWithGroupsAndNgContainer, SelectWithFormFieldLabel, SelectWithChangeEvent, + SelectInsideDynamicFormGroup, ]); })); @@ -1985,6 +1987,20 @@ describe('MDC-based MatSelect', () => { expect(fixture.componentInstance.select.panelOpen) .toBe(true, `Expected select panelOpen property to become true.`); })); + + it('should keep the disabled state in sync if the form group is swapped and ' + + 'disabled at the same time', fakeAsync(() => { + const fixture = TestBed.createComponent(SelectInsideDynamicFormGroup); + fixture.detectChanges(); + const instance = fixture.componentInstance; + + expect(instance.select.disabled).toBe(false); + + instance.assignGroup(true); + fixture.detectChanges(); + + expect(instance.select.disabled).toBe(true); + })); }); describe('keyboard scrolling', () => { @@ -4608,3 +4624,30 @@ class SelectWithResetOptionAndFormControl { ` }) class SelectInNgContainer {} + + +@Component({ + template: ` +
+ + + One + + +
+ ` +}) +class SelectInsideDynamicFormGroup { + @ViewChild(MatSelect) select: MatSelect; + form: FormGroup; + + constructor(private _formBuilder: FormBuilder) { + this.assignGroup(false); + } + + assignGroup(isDisabled: boolean) { + this.form = this._formBuilder.group({ + control: {value: '', disabled: isDisabled} + }); + } +} diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index 73ca9fd7b3c5..ab9963704b91 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -50,6 +50,7 @@ import { NG_VALUE_ACCESSOR, ReactiveFormsModule, Validators, + FormBuilder, } from '@angular/forms'; import { ErrorStateMatcher, @@ -133,6 +134,7 @@ describe('MatSelect', () => { SelectWithGroupsAndNgContainer, SelectWithFormFieldLabel, SelectWithChangeEvent, + SelectInsideDynamicFormGroup, ]); })); @@ -1999,6 +2001,20 @@ describe('MatSelect', () => { expect(fixture.componentInstance.select.panelOpen) .toBe(true, `Expected select panelOpen property to become true.`); })); + + it('should keep the disabled state in sync if the form group is swapped and ' + + 'disabled at the same time', fakeAsync(() => { + const fixture = TestBed.createComponent(SelectInsideDynamicFormGroup); + fixture.detectChanges(); + const instance = fixture.componentInstance; + + expect(instance.select.disabled).toBe(false); + + instance.assignGroup(true); + fixture.detectChanges(); + + expect(instance.select.disabled).toBe(true); + })); }); describe('animations', () => { @@ -5507,3 +5523,29 @@ class SelectWithResetOptionAndFormControl { ` }) class SelectInNgContainer {} + +@Component({ + template: ` +
+ + + One + + +
+ ` +}) +class SelectInsideDynamicFormGroup { + @ViewChild(MatSelect) select: MatSelect; + form: FormGroup; + + constructor(private _formBuilder: FormBuilder) { + this.assignGroup(false); + } + + assignGroup(isDisabled: boolean) { + this.form = this._formBuilder.group({ + control: {value: '', disabled: isDisabled} + }); + } +} diff --git a/src/material/select/select.ts b/src/material/select/select.ts index cfcc0a5e5296..a9ddeecb06e9 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -561,6 +561,11 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A } if (this.ngControl) { + // The disabled state might go out of sync if the form group is swapped out. See #17860. + if (this.ngControl.disabled !== this.disabled) { + this.disabled = !!this.ngControl.disabled; + } + this.updateErrorState(); } }