Skip to content

Commit 7a9b1dc

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 2111bbf commit 7a9b1dc

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

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

Lines changed: 45 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,
@@ -123,6 +124,7 @@ describe('MDC-based MatSelect', () => {
123124
SelectWithGroupsAndNgContainer,
124125
SelectWithFormFieldLabel,
125126
SelectWithChangeEvent,
127+
SelectInsideDynamicFormGroup,
126128
]);
127129
}),
128130
);
@@ -2193,6 +2195,23 @@ describe('MDC-based MatSelect', () => {
21932195
.withContext(`Expected select panelOpen property to become true.`)
21942196
.toBe(true);
21952197
}));
2198+
2199+
it(
2200+
'should keep the disabled state in sync if the form group is swapped and ' +
2201+
'disabled at the same time',
2202+
fakeAsync(() => {
2203+
const fixture = TestBed.createComponent(SelectInsideDynamicFormGroup);
2204+
fixture.detectChanges();
2205+
const instance = fixture.componentInstance;
2206+
2207+
expect(instance.select.disabled).toBe(false);
2208+
2209+
instance.assignGroup(true);
2210+
fixture.detectChanges();
2211+
2212+
expect(instance.select.disabled).toBe(true);
2213+
}),
2214+
);
21962215
});
21972216

21982217
describe('keyboard scrolling', () => {
@@ -5036,3 +5055,29 @@ class SelectWithResetOptionAndFormControl {
50365055
`,
50375056
})
50385057
class SelectInNgContainer {}
5058+
5059+
@Component({
5060+
template: `
5061+
<form [formGroup]="form">
5062+
<mat-form-field>
5063+
<mat-select formControlName="control">
5064+
<mat-option value="1">One</mat-option>
5065+
</mat-select>
5066+
</mat-form-field>
5067+
</form>
5068+
`,
5069+
})
5070+
class SelectInsideDynamicFormGroup {
5071+
@ViewChild(MatSelect) select: MatSelect;
5072+
form: FormGroup;
5073+
5074+
constructor(private _formBuilder: FormBuilder) {
5075+
this.assignGroup(false);
5076+
}
5077+
5078+
assignGroup(isDisabled: boolean) {
5079+
this.form = this._formBuilder.group({
5080+
control: {value: '', disabled: isDisabled},
5081+
});
5082+
}
5083+
}

src/material/select/select.spec.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import {
4949
NG_VALUE_ACCESSOR,
5050
ReactiveFormsModule,
5151
Validators,
52+
FormBuilder,
5253
} from '@angular/forms';
5354
import {ErrorStateMatcher, MatOption, MatOptionSelectionChange} from '@angular/material/core';
5455
import {
@@ -122,6 +123,7 @@ describe('MatSelect', () => {
122123
SelectWithGroupsAndNgContainer,
123124
SelectWithFormFieldLabel,
124125
SelectWithChangeEvent,
126+
SelectInsideDynamicFormGroup,
125127
]);
126128
}),
127129
);
@@ -2208,6 +2210,23 @@ describe('MatSelect', () => {
22082210
.withContext(`Expected select panelOpen property to become true.`)
22092211
.toBe(true);
22102212
}));
2213+
2214+
it(
2215+
'should keep the disabled state in sync if the form group is swapped and ' +
2216+
'disabled at the same time',
2217+
fakeAsync(() => {
2218+
const fixture = TestBed.createComponent(SelectInsideDynamicFormGroup);
2219+
fixture.detectChanges();
2220+
const instance = fixture.componentInstance;
2221+
2222+
expect(instance.select.disabled).toBe(false);
2223+
2224+
instance.assignGroup(true);
2225+
fixture.detectChanges();
2226+
2227+
expect(instance.select.disabled).toBe(true);
2228+
}),
2229+
);
22112230
});
22122231

22132232
describe('animations', () => {
@@ -6017,3 +6036,29 @@ class SelectWithResetOptionAndFormControl {
60176036
`,
60186037
})
60196038
class SelectInNgContainer {}
6039+
6040+
@Component({
6041+
template: `
6042+
<form [formGroup]="form">
6043+
<mat-form-field>
6044+
<mat-select formControlName="control">
6045+
<mat-option value="1">One</mat-option>
6046+
</mat-select>
6047+
</mat-form-field>
6048+
</form>
6049+
`,
6050+
})
6051+
class SelectInsideDynamicFormGroup {
6052+
@ViewChild(MatSelect) select: MatSelect;
6053+
form: FormGroup;
6054+
6055+
constructor(private _formBuilder: FormBuilder) {
6056+
this.assignGroup(false);
6057+
}
6058+
6059+
assignGroup(isDisabled: boolean) {
6060+
this.form = this._formBuilder.group({
6061+
control: {value: '', disabled: isDisabled},
6062+
});
6063+
}
6064+
}

src/material/select/select.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,11 @@ export abstract class _MatSelectBase<C>
586586
}
587587

588588
if (this.ngControl) {
589+
// The disabled state might go out of sync if the form group is swapped out. See #17860.
590+
if (this.ngControl.disabled !== this.disabled) {
591+
this.disabled = !!this.ngControl.disabled;
592+
}
593+
589594
this.updateErrorState();
590595
}
591596
}

0 commit comments

Comments
 (0)