Skip to content

Commit 1d1247c

Browse files
authored
fix(material/chips): selectable="false" doesn't work on initial assignment (#24906)
Fixes #24903.
1 parent c95ecbe commit 1d1247c

File tree

3 files changed

+120
-5
lines changed

3 files changed

+120
-5
lines changed

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,34 @@ describe('MDC-based MatChipListbox', () => {
470470
.withContext('Expect no selected chips')
471471
.toBeUndefined();
472472
});
473+
474+
it('should not select when is not selectable', fakeAsync(() => {
475+
fixture.destroy();
476+
TestBed.resetTestingModule();
477+
478+
const falsyFixture = createComponent(FalsyBasicChipListbox);
479+
falsyFixture.detectChanges();
480+
tick();
481+
falsyFixture.detectChanges();
482+
483+
const chipListboxElement = falsyFixture.debugElement.query(By.directive(MatChipListbox))!;
484+
const _chips = chipListboxElement.componentInstance._chips;
485+
const nativeChips = (
486+
chipListboxElement.nativeElement as HTMLElement
487+
).querySelectorAll<HTMLElement>('.mdc-evolution-chip__action--primary');
488+
489+
expect(_chips.first.selected)
490+
.withContext('Expected first option not to be selected')
491+
.toBe(false);
492+
493+
dispatchKeyboardEvent(nativeChips[0], 'keydown', SPACE);
494+
falsyFixture.detectChanges();
495+
flush();
496+
497+
expect(_chips.first.selected)
498+
.withContext('Expected first option not to be selected.')
499+
.toBe(false);
500+
}));
473501
});
474502

475503
describe('chip list with chip input', () => {
@@ -874,3 +902,33 @@ class SelectedChipListbox {
874902
];
875903
@ViewChildren(MatChipOption) chips: QueryList<MatChipOption>;
876904
}
905+
906+
@Component({
907+
template: `
908+
<mat-chip-listbox [formControl]="control" [required]="isRequired"
909+
[tabIndex]="tabIndexOverride" [selectable]="selectable">
910+
<mat-chip-option *ngFor="let food of foods" [value]="food.value" [disabled]="food.disabled">
911+
{{ food.viewValue }}
912+
</mat-chip-option>
913+
</mat-chip-listbox>
914+
`,
915+
})
916+
class FalsyBasicChipListbox {
917+
foods: any[] = [
918+
{value: 'steak-0', viewValue: 'Steak'},
919+
{value: 'pizza-1', viewValue: 'Pizza'},
920+
{value: 'tacos-2', viewValue: 'Tacos', disabled: true},
921+
{value: 'sandwich-3', viewValue: 'Sandwich'},
922+
{value: 'chips-4', viewValue: 'Chips'},
923+
{value: 'eggs-5', viewValue: 'Eggs'},
924+
{value: 'pasta-6', viewValue: 'Pasta'},
925+
{value: 'sushi-7', viewValue: 'Sushi'},
926+
];
927+
control = new FormControl<string | null>(null);
928+
isRequired: boolean;
929+
tabIndexOverride: number;
930+
selectable: boolean = false;
931+
932+
@ViewChild(MatChipListbox) chipListbox: MatChipListbox;
933+
@ViewChildren(MatChipOption) chips: QueryList<MatChipOption>;
934+
}

src/material/legacy-chips/chip-list.spec.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,33 @@ describe('MatChipList', () => {
748748
.withContext('Expect no selected chips')
749749
.toBeUndefined();
750750
});
751+
752+
it('should not select when is not selectable', fakeAsync(() => {
753+
fixture.destroy();
754+
TestBed.resetTestingModule();
755+
756+
const falsyFixture = createComponent(FalsyBasicChipList);
757+
falsyFixture.detectChanges();
758+
tick();
759+
falsyFixture.detectChanges();
760+
761+
const chipListElement = falsyFixture.debugElement.query(By.directive(MatLegacyChipList))!;
762+
const currentChips = chipListElement.componentInstance.chips;
763+
const currentNativeChips = falsyFixture.debugElement
764+
.queryAll(By.css('mat-chip'))
765+
.map(chip => chip.nativeElement);
766+
767+
expect(currentChips.first.selected)
768+
.withContext('Expected first option not to be selected')
769+
.toBe(false);
770+
771+
dispatchKeyboardEvent(currentNativeChips[0], 'keydown', SPACE);
772+
falsyFixture.detectChanges();
773+
774+
expect(currentChips.first.selected)
775+
.withContext('Expected first option not to be selected.')
776+
.toBe(false);
777+
}));
751778
});
752779

753780
describe('forms integration', () => {
@@ -1866,3 +1893,35 @@ class ChipListInsideDynamicFormGroup {
18661893
});
18671894
}
18681895
}
1896+
1897+
@Component({
1898+
selector: 'basic-chip-list',
1899+
template: `
1900+
<mat-form-field>
1901+
<mat-chip-list placeholder="Food" [formControl]="control"
1902+
[tabIndex]="tabIndexOverride" [selectable]="selectable">
1903+
<mat-chip *ngFor="let food of foods" [value]="food.value" [disabled]="food.disabled">
1904+
{{ food.viewValue }}
1905+
</mat-chip>
1906+
</mat-chip-list>
1907+
</mat-form-field>
1908+
`,
1909+
})
1910+
class FalsyBasicChipList {
1911+
foods: any[] = [
1912+
{value: 'steak-0', viewValue: 'Steak'},
1913+
{value: 'pizza-1', viewValue: 'Pizza'},
1914+
{value: 'tacos-2', viewValue: 'Tacos', disabled: true},
1915+
{value: 'sandwich-3', viewValue: 'Sandwich'},
1916+
{value: 'chips-4', viewValue: 'Chips'},
1917+
{value: 'eggs-5', viewValue: 'Eggs'},
1918+
{value: 'pasta-6', viewValue: 'Pasta'},
1919+
{value: 'sushi-7', viewValue: 'Sushi'},
1920+
];
1921+
control = new FormControl<string | null>(null);
1922+
tabIndexOverride: number;
1923+
selectable: boolean = false;
1924+
1925+
@ViewChild(MatLegacyChipList) chipList: MatLegacyChipList;
1926+
@ViewChildren(MatLegacyChip) chips: QueryList<MatLegacyChip>;
1927+
}

src/material/legacy-chips/chip-list.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,7 @@ export class MatLegacyChipList
329329
}
330330
set selectable(value: BooleanInput) {
331331
this._selectable = coerceBooleanProperty(value);
332-
333-
if (this.chips) {
334-
this.chips.forEach(chip => (chip.chipListSelectable = this._selectable));
335-
}
332+
this._syncChipsState();
336333
}
337334
protected _selectable: boolean = true;
338335

@@ -414,7 +411,7 @@ export class MatLegacyChipList
414411

415412
// When the list changes, re-subscribe
416413
this.chips.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => {
417-
if (this.disabled) {
414+
if (this.disabled || !this.selectable) {
418415
// Since this happens after the content has been
419416
// checked, we need to defer it to the next tick.
420417
Promise.resolve().then(() => {
@@ -844,6 +841,7 @@ export class MatLegacyChipList
844841
this.chips.forEach(chip => {
845842
chip._chipListDisabled = this._disabled;
846843
chip._chipListMultiple = this.multiple;
844+
chip.chipListSelectable = this._selectable;
847845
});
848846
}
849847
}

0 commit comments

Comments
 (0)