diff --git a/src/lib/chips/chip.spec.ts b/src/lib/chips/chip.spec.ts index 9a0328f3df95..25416a371835 100644 --- a/src/lib/chips/chip.spec.ts +++ b/src/lib/chips/chip.spec.ts @@ -150,6 +150,55 @@ describe('Chips', () => { expect(event.defaultPrevented).toBe(true); }); + it('should not dispatch `selectionChange` event when deselecting a non-selected chip', () => { + chipInstance.deselect(); + + const spy = jasmine.createSpy('selectionChange spy'); + const subscription = chipInstance.selectionChange.subscribe(spy); + + chipInstance.deselect(); + + expect(spy).not.toHaveBeenCalled(); + subscription.unsubscribe(); + }); + + it('should not dispatch `selectionChange` event when selecting a selected chip', () => { + chipInstance.select(); + + const spy = jasmine.createSpy('selectionChange spy'); + const subscription = chipInstance.selectionChange.subscribe(spy); + + chipInstance.select(); + + expect(spy).not.toHaveBeenCalled(); + subscription.unsubscribe(); + }); + + it('should not dispatch `selectionChange` event when selecting a selected chip via ' + + 'user interaction', () => { + chipInstance.select(); + + const spy = jasmine.createSpy('selectionChange spy'); + const subscription = chipInstance.selectionChange.subscribe(spy); + + chipInstance.selectViaInteraction(); + + expect(spy).not.toHaveBeenCalled(); + subscription.unsubscribe(); + }); + + it('should not dispatch `selectionChange` through setter if the value did not change', () => { + chipInstance.selected = false; + + const spy = jasmine.createSpy('selectionChange spy'); + const subscription = chipInstance.selectionChange.subscribe(spy); + + chipInstance.selected = false; + + expect(spy).not.toHaveBeenCalled(); + subscription.unsubscribe(); + }); + }); describe('keyboard behavior', () => { diff --git a/src/lib/chips/chip.ts b/src/lib/chips/chip.ts index 99f9d0e04fea..d53e3c08ee26 100644 --- a/src/lib/chips/chip.ts +++ b/src/lib/chips/chip.ts @@ -159,12 +159,12 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes @Input() get selected(): boolean { return this._selected; } set selected(value: boolean) { - this._selected = coerceBooleanProperty(value); - this.selectionChange.emit({ - source: this, - isUserInput: false, - selected: value - }); + const coercedValue = coerceBooleanProperty(value); + + if (coercedValue !== this._selected) { + this._selected = coercedValue; + this._dispatchSelectionChange(); + } } protected _selected: boolean = false; @@ -262,45 +262,32 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes /** Selects the chip. */ select(): void { - this._selected = true; - this.selectionChange.emit({ - source: this, - isUserInput: false, - selected: true - }); + if (!this._selected) { + this._selected = true; + this._dispatchSelectionChange(); + } } /** Deselects the chip. */ deselect(): void { - this._selected = false; - this.selectionChange.emit({ - source: this, - isUserInput: false, - selected: false - }); + if (this._selected) { + this._selected = false; + this._dispatchSelectionChange(); + } } /** Select this chip and emit selected event */ selectViaInteraction(): void { - this._selected = true; - // Emit select event when selected changes. - this.selectionChange.emit({ - source: this, - isUserInput: true, - selected: true - }); + if (!this._selected) { + this._selected = true; + this._dispatchSelectionChange(true); + } } /** Toggles the current selected state of this chip. */ toggleSelected(isUserInput: boolean = false): boolean { this._selected = !this.selected; - - this.selectionChange.emit({ - source: this, - isUserInput, - selected: this._selected - }); - + this._dispatchSelectionChange(isUserInput); return this.selected; } @@ -375,6 +362,14 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes }); }); } + + private _dispatchSelectionChange(isUserInput = false) { + this.selectionChange.emit({ + source: this, + isUserInput, + selected: this._selected + }); + } }