Skip to content

Commit 86ebb9b

Browse files
authored
fix(material/chips): chip set overwriting disabled state (angular#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 angular#29783.
1 parent 030cdd6 commit 86ebb9b

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
@@ -158,12 +158,10 @@ export class MatChipSet implements AfterViewInit, OnDestroy {
158158

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

169167
/** 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
@@ -158,6 +158,9 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck
158158
/** Id of a span that contains this chip's aria description. */
159159
_ariaDescriptionId = `${this.id}-aria-description`;
160160

161+
/** Whether the chip list is disabled. */
162+
_chipListDisabled: boolean = false;
163+
161164
private _textElement!: HTMLElement;
162165

163166
/**
@@ -201,7 +204,13 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck
201204

202205
/** Whether the chip is disabled. */
203206
@Input({transform: booleanAttribute})
204-
disabled: boolean = false;
207+
get disabled(): boolean {
208+
return this._disabled || this._chipListDisabled;
209+
}
210+
set disabled(value: boolean) {
211+
this._disabled = value;
212+
}
213+
private _disabled = false;
205214

206215
/** Emitted when a chip is to be removed. */
207216
@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
@@ -58,9 +58,11 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck
5858
protected basicChipAttrName: string;
5959
// (undocumented)
6060
_changeDetectorRef: ChangeDetectorRef;
61+
_chipListDisabled: boolean;
6162
color?: string | null;
6263
readonly destroyed: EventEmitter<MatChipEvent>;
63-
disabled: boolean;
64+
get disabled(): boolean;
65+
set disabled(value: boolean);
6466
disableRipple: boolean;
6567
// (undocumented)
6668
protected _document: Document;

0 commit comments

Comments
 (0)