Skip to content

Commit ca2ce61

Browse files
volvachevEgor Volvachev
authored andcommitted
fix(material/chips): selectable="false" doesn't work on initial assignment
Fixes #24903.
1 parent 567be4f commit ca2ce61

File tree

3 files changed

+122
-5
lines changed

3 files changed

+122
-5
lines changed

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,36 @@ describe('MDC-based MatChipListbox', () => {
461461
.withContext('Expect no selected chips')
462462
.toBeUndefined();
463463
});
464+
465+
it('should not select when is not selectable', fakeAsync(() => {
466+
fixture.destroy();
467+
TestBed.resetTestingModule();
468+
469+
const falsyFixture = createComponent(FalsyBasicChipListbox);
470+
falsyFixture.detectChanges();
471+
tick();
472+
falsyFixture.detectChanges();
473+
474+
const chipListboxDebugElement = falsyFixture.debugElement.query(
475+
By.directive(MatChipListbox),
476+
)!;
477+
const chips = chipListboxDebugElement.componentInstance._chips;
478+
const nativeChips = (
479+
chipListboxDebugElement.nativeElement as HTMLElement
480+
).querySelectorAll<HTMLElement>('.mdc-evolution-chip__action--primary');
481+
482+
expect(chips.first.selected)
483+
.withContext('Expected first option not to be selected')
484+
.toBe(false);
485+
486+
dispatchKeyboardEvent(nativeChips[0], 'keydown', SPACE);
487+
falsyFixture.detectChanges();
488+
flush();
489+
490+
expect(chips.first.selected)
491+
.withContext('Expected first option not to be selected.')
492+
.toBe(false);
493+
}));
464494
});
465495

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

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

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,33 @@ describe('MatChipList', () => {
743743
.withContext('Expect no selected chips')
744744
.toBeUndefined();
745745
});
746+
747+
it('should not select when is not selectable', fakeAsync(() => {
748+
fixture.destroy();
749+
TestBed.resetTestingModule();
750+
751+
const falsyFixture = createComponent(FalsyBasicChipList);
752+
falsyFixture.detectChanges();
753+
tick();
754+
falsyFixture.detectChanges();
755+
756+
const chipListDebugElement = falsyFixture.debugElement.query(By.directive(MatChipList))!;
757+
const chips = chipListDebugElement.componentInstance.chips;
758+
const nativeChips = falsyFixture.debugElement
759+
.queryAll(By.css('mat-chip'))
760+
.map(chip => chip.nativeElement);
761+
762+
expect(chips.first.selected)
763+
.withContext('Expected first option not to be selected')
764+
.toBe(false);
765+
766+
dispatchKeyboardEvent(nativeChips[0], 'keydown', SPACE);
767+
falsyFixture.detectChanges();
768+
769+
expect(chips.first.selected)
770+
.withContext('Expected first option not to be selected.')
771+
.toBe(false);
772+
}));
746773
});
747774

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

src/material/chips/chip-list.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -329,10 +329,7 @@ export class MatChipList
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 MatChipList
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 MatChipList
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)