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 Dec 6, 2020
1 parent 6ca1e43 commit 46a247d
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
42 changes: 42 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 @@ -1985,6 +1986,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);
const instance = fixture.componentInstance;
fixture.detectChanges();

expect(instance.select.disabled).toBe(false);

instance.assignGroup(true);
fixture.detectChanges();

expect(instance.select.disabled).toBe(true);
}));
});

describe('keyboard scrolling', () => {
Expand Down Expand Up @@ -4608,3 +4623,30 @@ 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}
});
}
}
42 changes: 42 additions & 0 deletions src/material/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
NG_VALUE_ACCESSOR,
ReactiveFormsModule,
Validators,
FormBuilder,
} from '@angular/forms';
import {
ErrorStateMatcher,
Expand Down Expand Up @@ -133,6 +134,7 @@ describe('MatSelect', () => {
SelectWithGroupsAndNgContainer,
SelectWithFormFieldLabel,
SelectWithChangeEvent,
SelectInsideDynamicFormGroup,
]);
}));

Expand Down Expand Up @@ -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);
const instance = fixture.componentInstance;
fixture.detectChanges();

expect(instance.select.disabled).toBe(false);

instance.assignGroup(true);
fixture.detectChanges();

expect(instance.select.disabled).toBe(true);
}));
});

describe('animations', () => {
Expand Down Expand Up @@ -5507,3 +5523,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 @@ -555,6 +555,11 @@ export abstract class _MatSelectBase<C> 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();
}
}
Expand Down

0 comments on commit 46a247d

Please sign in to comment.