From 7a5c1dfb46b12c6ba99b7448fc458342d8ef6629 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Mon, 30 Sep 2024 19:53:28 +0200 Subject: [PATCH] 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 86ebb9bfd55e637be1e6d0117a10e290c5247ebd) --- src/material/chips/chip-listbox.spec.ts | 23 +++++++++++++++++++++++ src/material/chips/chip-set.ts | 10 ++++------ src/material/chips/chip.ts | 11 ++++++++++- tools/public_api_guard/material/chips.md | 4 +++- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/material/chips/chip-listbox.spec.ts b/src/material/chips/chip-listbox.spec.ts index b87a91e7a7b9..1de4a5c0747e 100644 --- a/src/material/chips/chip-listbox.spec.ts +++ b/src/material/chips/chip-listbox.spec.ts @@ -113,6 +113,15 @@ describe('MatChipListbox', () => { expect(chipListboxNativeElement.hasAttribute('role')).toBe(false); expect(chipListboxNativeElement.hasAttribute('aria-required')).toBe(false); }); + + it('should toggle the chips disabled state based on whether it is disabled', fakeAsync(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + const disabledFixture = createComponent(IndividuallyDisabledChipInsideForm); + disabledFixture.detectChanges(); + flush(); + expect(disabledFixture.componentInstance.chip.disabled).toBe(true); + })); }); describe('with selected chips', () => { @@ -1043,3 +1052,17 @@ class FalsyBasicChipListbox { @ViewChild(MatChipListbox) chipListbox: MatChipListbox; @ViewChildren(MatChipOption) chips: QueryList; } + +// Based on #29783. +@Component({ + template: ` +
+ + Hello + +
+ `, +}) +class IndividuallyDisabledChipInsideForm { + @ViewChild(MatChipOption) chip: MatChipOption; +} diff --git a/src/material/chips/chip-set.ts b/src/material/chips/chip-set.ts index d29f9b1250e6..7be9787fdd39 100644 --- a/src/material/chips/chip-set.ts +++ b/src/material/chips/chip-set.ts @@ -157,12 +157,10 @@ export class MatChipSet implements AfterViewInit, OnDestroy { /** Syncs the chip-set's state with the individual chips. */ protected _syncChipsState() { - if (this._chips) { - this._chips.forEach(chip => { - chip.disabled = this._disabled; - chip._changeDetectorRef.markForCheck(); - }); - } + this._chips?.forEach(chip => { + chip._chipListDisabled = this._disabled; + chip._changeDetectorRef.markForCheck(); + }); } /** Dummy method for subclasses to override. Base chip set cannot be focused. */ diff --git a/src/material/chips/chip.ts b/src/material/chips/chip.ts index d489f9766168..a4f305149578 100644 --- a/src/material/chips/chip.ts +++ b/src/material/chips/chip.ts @@ -153,6 +153,9 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck /** Id of a span that contains this chip's aria description. */ _ariaDescriptionId = `${this.id}-aria-description`; + /** Whether the chip list is disabled. */ + _chipListDisabled: boolean = false; + private _textElement!: HTMLElement; /** @@ -196,7 +199,13 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck /** Whether the chip is disabled. */ @Input({transform: booleanAttribute}) - disabled: boolean = false; + get disabled(): boolean { + return this._disabled || this._chipListDisabled; + } + set disabled(value: boolean) { + this._disabled = value; + } + private _disabled = false; /** Emitted when a chip is to be removed. */ @Output() readonly removed: EventEmitter = new EventEmitter(); diff --git a/tools/public_api_guard/material/chips.md b/tools/public_api_guard/material/chips.md index 7a387fa1dcfa..862bbc8cfe59 100644 --- a/tools/public_api_guard/material/chips.md +++ b/tools/public_api_guard/material/chips.md @@ -66,9 +66,11 @@ export class MatChip implements OnInit, AfterViewInit, AfterContentInit, DoCheck protected basicChipAttrName: string; // (undocumented) _changeDetectorRef: ChangeDetectorRef; + _chipListDisabled: boolean; color?: string | null; readonly destroyed: EventEmitter; - disabled: boolean; + get disabled(): boolean; + set disabled(value: boolean); disableRipple: boolean; // (undocumented) protected _document: Document;