Skip to content

Commit

Permalink
fix(material/select): disabled state out of sync when swapping form g…
Browse files Browse the repository at this point in the history
…roup 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 angular#17860.
  • Loading branch information
crisbeto committed Mar 3, 2022
1 parent 2111bbf commit 7a9b1dc
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/material-experimental/mdc-select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
} from '@angular/core/testing';
import {
ControlValueAccessor,
FormBuilder,
FormControl,
FormGroup,
FormGroupDirective,
Expand Down Expand Up @@ -123,6 +124,7 @@ describe('MDC-based MatSelect', () => {
SelectWithGroupsAndNgContainer,
SelectWithFormFieldLabel,
SelectWithChangeEvent,
SelectInsideDynamicFormGroup,
]);
}),
);
Expand Down Expand Up @@ -2193,6 +2195,23 @@ describe('MDC-based MatSelect', () => {
.withContext(`Expected select panelOpen property to become true.`)
.toBe(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', () => {
Expand Down Expand Up @@ -5036,3 +5055,29 @@ class SelectWithResetOptionAndFormControl {
`,
})
class SelectInNgContainer {}

@Component({
template: `
<form [formGroup]="form">
<mat-form-field>
<mat-select formControlName="control">
<mat-option value="1">One</mat-option>
</mat-select>
</mat-form-field>
</form>
`,
})
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},
});
}
}
45 changes: 45 additions & 0 deletions src/material/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
NG_VALUE_ACCESSOR,
ReactiveFormsModule,
Validators,
FormBuilder,
} from '@angular/forms';
import {ErrorStateMatcher, MatOption, MatOptionSelectionChange} from '@angular/material/core';
import {
Expand Down Expand Up @@ -122,6 +123,7 @@ describe('MatSelect', () => {
SelectWithGroupsAndNgContainer,
SelectWithFormFieldLabel,
SelectWithChangeEvent,
SelectInsideDynamicFormGroup,
]);
}),
);
Expand Down Expand Up @@ -2208,6 +2210,23 @@ describe('MatSelect', () => {
.withContext(`Expected select panelOpen property to become true.`)
.toBe(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', () => {
Expand Down Expand Up @@ -6017,3 +6036,29 @@ class SelectWithResetOptionAndFormControl {
`,
})
class SelectInNgContainer {}

@Component({
template: `
<form [formGroup]="form">
<mat-form-field>
<mat-select formControlName="control">
<mat-option value="1">One</mat-option>
</mat-select>
</mat-form-field>
</form>
`,
})
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},
});
}
}
5 changes: 5 additions & 0 deletions src/material/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,11 @@ export abstract class _MatSelectBase<C>
}

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();
}
}
Expand Down

0 comments on commit 7a9b1dc

Please sign in to comment.