Skip to content

Commit 19af7ae

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

File tree

3 files changed

+120
-5
lines changed

3 files changed

+120
-5
lines changed

src/material-experimental/mdc-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/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 chipListElement = falsyFixture.debugElement.query(By.directive(MatChipList))!;
757+
const currentChips = chipListElement.componentInstance.chips;
758+
const currentNativeChips = falsyFixture.debugElement
759+
.queryAll(By.css('mat-chip'))
760+
.map(chip => chip.nativeElement);
761+
762+
expect(currentChips.first.selected)
763+
.withContext('Expected first option not to be selected')
764+
.toBe(false);
765+
766+
dispatchKeyboardEvent(currentNativeChips[0], 'keydown', SPACE);
767+
falsyFixture.detectChanges();
768+
769+
expect(currentChips.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)