Skip to content

Commit 46a247d

Browse files
committed
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.
1 parent 6ca1e43 commit 46a247d

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

src/material-experimental/mdc-select/select.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
} from '@angular/core/testing';
4343
import {
4444
ControlValueAccessor,
45+
FormBuilder,
4546
FormControl,
4647
FormGroup,
4748
FormGroupDirective,
@@ -1985,6 +1986,20 @@ describe('MDC-based MatSelect', () => {
19851986
expect(fixture.componentInstance.select.panelOpen)
19861987
.toBe(true, `Expected select panelOpen property to become true.`);
19871988
}));
1989+
1990+
it('should keep the disabled state in sync if the form group is swapped and ' +
1991+
'disabled at the same time', fakeAsync(() => {
1992+
const fixture = TestBed.createComponent(SelectInsideDynamicFormGroup);
1993+
const instance = fixture.componentInstance;
1994+
fixture.detectChanges();
1995+
1996+
expect(instance.select.disabled).toBe(false);
1997+
1998+
instance.assignGroup(true);
1999+
fixture.detectChanges();
2000+
2001+
expect(instance.select.disabled).toBe(true);
2002+
}));
19882003
});
19892004

19902005
describe('keyboard scrolling', () => {
@@ -4608,3 +4623,30 @@ class SelectWithResetOptionAndFormControl {
46084623
`
46094624
})
46104625
class SelectInNgContainer {}
4626+
4627+
4628+
@Component({
4629+
template: `
4630+
<form [formGroup]="form">
4631+
<mat-form-field>
4632+
<mat-select formControlName="control">
4633+
<mat-option value="1">One</mat-option>
4634+
</mat-select>
4635+
</mat-form-field>
4636+
</form>
4637+
`
4638+
})
4639+
class SelectInsideDynamicFormGroup {
4640+
@ViewChild(MatSelect) select: MatSelect;
4641+
form: FormGroup;
4642+
4643+
constructor(private _formBuilder: FormBuilder) {
4644+
this.assignGroup(false);
4645+
}
4646+
4647+
assignGroup(isDisabled: boolean) {
4648+
this.form = this._formBuilder.group({
4649+
control: {value: '', disabled: isDisabled}
4650+
});
4651+
}
4652+
}

src/material/select/select.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
NG_VALUE_ACCESSOR,
5151
ReactiveFormsModule,
5252
Validators,
53+
FormBuilder,
5354
} from '@angular/forms';
5455
import {
5556
ErrorStateMatcher,
@@ -133,6 +134,7 @@ describe('MatSelect', () => {
133134
SelectWithGroupsAndNgContainer,
134135
SelectWithFormFieldLabel,
135136
SelectWithChangeEvent,
137+
SelectInsideDynamicFormGroup,
136138
]);
137139
}));
138140

@@ -1999,6 +2001,20 @@ describe('MatSelect', () => {
19992001
expect(fixture.componentInstance.select.panelOpen)
20002002
.toBe(true, `Expected select panelOpen property to become true.`);
20012003
}));
2004+
2005+
it('should keep the disabled state in sync if the form group is swapped and ' +
2006+
'disabled at the same time', fakeAsync(() => {
2007+
const fixture = TestBed.createComponent(SelectInsideDynamicFormGroup);
2008+
const instance = fixture.componentInstance;
2009+
fixture.detectChanges();
2010+
2011+
expect(instance.select.disabled).toBe(false);
2012+
2013+
instance.assignGroup(true);
2014+
fixture.detectChanges();
2015+
2016+
expect(instance.select.disabled).toBe(true);
2017+
}));
20022018
});
20032019

20042020
describe('animations', () => {
@@ -5507,3 +5523,29 @@ class SelectWithResetOptionAndFormControl {
55075523
`
55085524
})
55095525
class SelectInNgContainer {}
5526+
5527+
@Component({
5528+
template: `
5529+
<form [formGroup]="form">
5530+
<mat-form-field>
5531+
<mat-select formControlName="control">
5532+
<mat-option value="1">One</mat-option>
5533+
</mat-select>
5534+
</mat-form-field>
5535+
</form>
5536+
`
5537+
})
5538+
class SelectInsideDynamicFormGroup {
5539+
@ViewChild(MatSelect) select: MatSelect;
5540+
form: FormGroup;
5541+
5542+
constructor(private _formBuilder: FormBuilder) {
5543+
this.assignGroup(false);
5544+
}
5545+
5546+
assignGroup(isDisabled: boolean) {
5547+
this.form = this._formBuilder.group({
5548+
control: {value: '', disabled: isDisabled}
5549+
});
5550+
}
5551+
}

src/material/select/select.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,11 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
555555
}
556556

557557
if (this.ngControl) {
558+
// The disabled state might go out of sync if the form group is swapped out. See #17860.
559+
if (this.ngControl.disabled !== this.disabled) {
560+
this.disabled = !!this.ngControl.disabled;
561+
}
562+
558563
this.updateErrorState();
559564
}
560565
}

0 commit comments

Comments
 (0)