Skip to content

Commit 7a5c1df

Browse files
committed
fix(material/chips): chip set overwriting disabled state (#29795)
The chip set has been set up in a way where it syncs its state to the chips, instead of the other way around which we follow in other components. This means that if its `disabled` state changes later, it can ovewrite the state that the user explicitly set on the chip. These changes make the logic a bit more robust by writing to a different field. Fixes #29783. (cherry picked from commit 86ebb9b)
1 parent 0fabf52 commit 7a5c1df

File tree

4 files changed

+40
-8
lines changed

4 files changed

+40
-8
lines changed

src/material/chips/chip-listbox.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ describe('MatChipListbox', () => {
113113
expect(chipListboxNativeElement.hasAttribute('role')).toBe(false);
114114
expect(chipListboxNativeElement.hasAttribute('aria-required')).toBe(false);
115115
});
116+
117+
it('should toggle the chips disabled state based on whether it is disabled', fakeAsync(() => {
118+
fixture.destroy();
119+
TestBed.resetTestingModule();
120+
const disabledFixture = createComponent(IndividuallyDisabledChipInsideForm);
121+
disabledFixture.detectChanges();
122+
flush();
123+
expect(disabledFixture.componentInstance.chip.disabled).toBe(true);
124+
}));
116125
});
117126

118127
describe('with selected chips', () => {
@@ -1043,3 +1052,17 @@ class FalsyBasicChipListbox {
10431052
@ViewChild(MatChipListbox) chipListbox: MatChipListbox;
10441053
@ViewChildren(MatChipOption) chips: QueryList<MatChipOption>;
10451054
}
1055+
1056+
// Based on #29783.
1057+
@Component({
1058+
template: `
1059+
<form>
1060+
<mat-chip-listbox name="test" [ngModel]="null">
1061+
<mat-chip-option value="1" disabled>Hello</mat-chip-option>
1062+
</mat-chip-listbox>
1063+
</form>
1064+
`,
1065+
})
1066+
class IndividuallyDisabledChipInsideForm {
1067+
@ViewChild(MatChipOption) chip: MatChipOption;
1068+
}

src/material/chips/chip-set.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,10 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
157157

158158
/** Syncs the chip-set's state with the individual chips. */
159159
protected _syncChipsState() {
160-
if (this._chips) {
161-
this._chips.forEach(chip => {
162-
chip.disabled = this._disabled;
163-
chip._changeDetectorRef.markForCheck();
164-
});
165-
}
160+
this._chips?.forEach(chip => {
161+
chip._chipListDisabled = this._disabled;
162+
chip._changeDetectorRef.markForCheck();
163+
});
166164
}
167165

168166
/** Dummy method for subclasses to override. Base chip set cannot be focused. */

src/material/chips/chip.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck
153153
/** Id of a span that contains this chip's aria description. */
154154
_ariaDescriptionId = `${this.id}-aria-description`;
155155

156+
/** Whether the chip list is disabled. */
157+
_chipListDisabled: boolean = false;
158+
156159
private _textElement!: HTMLElement;
157160

158161
/**
@@ -196,7 +199,13 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck
196199

197200
/** Whether the chip is disabled. */
198201
@Input({transform: booleanAttribute})
199-
disabled: boolean = false;
202+
get disabled(): boolean {
203+
return this._disabled || this._chipListDisabled;
204+
}
205+
set disabled(value: boolean) {
206+
this._disabled = value;
207+
}
208+
private _disabled = false;
200209

201210
/** Emitted when a chip is to be removed. */
202211
@Output() readonly removed: EventEmitter<MatChipEvent> = new EventEmitter<MatChipEvent>();

tools/public_api_guard/material/chips.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck
6666
protected basicChipAttrName: string;
6767
// (undocumented)
6868
_changeDetectorRef: ChangeDetectorRef;
69+
_chipListDisabled: boolean;
6970
color?: string | null;
7071
readonly destroyed: EventEmitter<MatChipEvent>;
71-
disabled: boolean;
72+
get disabled(): boolean;
73+
set disabled(value: boolean);
7274
disableRipple: boolean;
7375
// (undocumented)
7476
protected _document: Document;

0 commit comments

Comments
 (0)