diff --git a/src/material-experimental/mdc-chips/chip-listbox.spec.ts b/src/material-experimental/mdc-chips/chip-listbox.spec.ts index 2161a0d43cb3..b2306cafcf12 100644 --- a/src/material-experimental/mdc-chips/chip-listbox.spec.ts +++ b/src/material-experimental/mdc-chips/chip-listbox.spec.ts @@ -470,6 +470,34 @@ describe('MDC-based MatChipListbox', () => { .withContext('Expect no selected chips') .toBeUndefined(); }); + + it('should not select when is not selectable', fakeAsync(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + + const falsyFixture = createComponent(FalsyBasicChipListbox); + falsyFixture.detectChanges(); + tick(); + falsyFixture.detectChanges(); + + const chipListboxElement = falsyFixture.debugElement.query(By.directive(MatChipListbox))!; + const _chips = chipListboxElement.componentInstance._chips; + const nativeChips = ( + chipListboxElement.nativeElement as HTMLElement + ).querySelectorAll('.mdc-evolution-chip__action--primary'); + + expect(_chips.first.selected) + .withContext('Expected first option not to be selected') + .toBe(false); + + dispatchKeyboardEvent(nativeChips[0], 'keydown', SPACE); + falsyFixture.detectChanges(); + flush(); + + expect(_chips.first.selected) + .withContext('Expected first option not to be selected.') + .toBe(false); + })); }); describe('chip list with chip input', () => { @@ -874,3 +902,33 @@ class SelectedChipListbox { ]; @ViewChildren(MatChipOption) chips: QueryList; } + +@Component({ + template: ` + + + {{ food.viewValue }} + + + `, +}) +class FalsyBasicChipListbox { + foods: any[] = [ + {value: 'steak-0', viewValue: 'Steak'}, + {value: 'pizza-1', viewValue: 'Pizza'}, + {value: 'tacos-2', viewValue: 'Tacos', disabled: true}, + {value: 'sandwich-3', viewValue: 'Sandwich'}, + {value: 'chips-4', viewValue: 'Chips'}, + {value: 'eggs-5', viewValue: 'Eggs'}, + {value: 'pasta-6', viewValue: 'Pasta'}, + {value: 'sushi-7', viewValue: 'Sushi'}, + ]; + control = new FormControl(null); + isRequired: boolean; + tabIndexOverride: number; + selectable: boolean = false; + + @ViewChild(MatChipListbox) chipListbox: MatChipListbox; + @ViewChildren(MatChipOption) chips: QueryList; +} diff --git a/src/material/chips/chip-list.spec.ts b/src/material/chips/chip-list.spec.ts index 528657485d66..dfe1fba873ec 100644 --- a/src/material/chips/chip-list.spec.ts +++ b/src/material/chips/chip-list.spec.ts @@ -743,6 +743,33 @@ describe('MatChipList', () => { .withContext('Expect no selected chips') .toBeUndefined(); }); + + it('should not select when is not selectable', fakeAsync(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + + const falsyFixture = createComponent(FalsyBasicChipList); + falsyFixture.detectChanges(); + tick(); + falsyFixture.detectChanges(); + + const chipListElement = falsyFixture.debugElement.query(By.directive(MatLegacyChipList))!; + const currentChips = chipListElement.componentInstance.chips; + const currentNativeChips = falsyFixture.debugElement + .queryAll(By.css('mat-chip')) + .map(chip => chip.nativeElement); + + expect(currentChips.first.selected) + .withContext('Expected first option not to be selected') + .toBe(false); + + dispatchKeyboardEvent(currentNativeChips[0], 'keydown', SPACE); + falsyFixture.detectChanges(); + + expect(currentChips.first.selected) + .withContext('Expected first option not to be selected.') + .toBe(false); + })); }); describe('forms integration', () => { @@ -1861,3 +1888,35 @@ class ChipListInsideDynamicFormGroup { }); } } + +@Component({ + selector: 'basic-chip-list', + template: ` + + + + {{ food.viewValue }} + + + + `, +}) +class FalsyBasicChipList { + foods: any[] = [ + {value: 'steak-0', viewValue: 'Steak'}, + {value: 'pizza-1', viewValue: 'Pizza'}, + {value: 'tacos-2', viewValue: 'Tacos', disabled: true}, + {value: 'sandwich-3', viewValue: 'Sandwich'}, + {value: 'chips-4', viewValue: 'Chips'}, + {value: 'eggs-5', viewValue: 'Eggs'}, + {value: 'pasta-6', viewValue: 'Pasta'}, + {value: 'sushi-7', viewValue: 'Sushi'}, + ]; + control = new FormControl(null); + tabIndexOverride: number; + selectable: boolean = false; + + @ViewChild(MatLegacyChipList) chipList: MatLegacyChipList; + @ViewChildren(MatLegacyChip) chips: QueryList; +} diff --git a/src/material/chips/chip-list.ts b/src/material/chips/chip-list.ts index 9fbeab038666..e4027476479e 100644 --- a/src/material/chips/chip-list.ts +++ b/src/material/chips/chip-list.ts @@ -329,10 +329,7 @@ export class MatChipList } set selectable(value: BooleanInput) { this._selectable = coerceBooleanProperty(value); - - if (this.chips) { - this.chips.forEach(chip => (chip.chipListSelectable = this._selectable)); - } + this._syncChipsState(); } protected _selectable: boolean = true; @@ -414,7 +411,7 @@ export class MatChipList // When the list changes, re-subscribe this.chips.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { - if (this.disabled) { + if (this.disabled || !this.selectable) { // Since this happens after the content has been // checked, we need to defer it to the next tick. Promise.resolve().then(() => { @@ -844,6 +841,7 @@ export class MatChipList this.chips.forEach(chip => { chip._chipListDisabled = this._disabled; chip._chipListMultiple = this.multiple; + chip.chipListSelectable = this._selectable; }); } }