Skip to content

Commit 0236623

Browse files
crisbetoandrewseguin
authored andcommitted
fix(chips): event propagation not stopped by remove button (#8772)
Fixes clicking on the chip remove button propagating up and potentially triggering its parent control. This is usually handled by the chip itself, however clicking on the button could remove the chip before it has the chance to stop propagation. Fixes #8771.
1 parent 9aabb14 commit 0236623

File tree

2 files changed

+27
-11
lines changed

2 files changed

+27
-11
lines changed

src/lib/chips/chip-remove.spec.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import {Component, DebugElement} from '@angular/core';
22
import {By} from '@angular/platform-browser';
3-
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
3+
import {fakeAsync, ComponentFixture, TestBed} from '@angular/core/testing';
44
import {MatChip, MatChipsModule} from './index';
5+
import {dispatchFakeEvent} from '@angular/cdk/testing';
56

67
describe('Chip Remove', () => {
78
let fixture: ComponentFixture<any>;
89
let testChip: TestChip;
910
let chipDebugElement: DebugElement;
1011
let chipNativeElement: HTMLElement;
1112

12-
beforeEach(async(() => {
13+
beforeEach(fakeAsync(() => {
1314
TestBed.configureTestingModule({
1415
imports: [MatChipsModule],
1516
declarations: [
@@ -18,9 +19,6 @@ describe('Chip Remove', () => {
1819
});
1920

2021
TestBed.compileComponents();
21-
}));
22-
23-
beforeEach(async(() => {
2422
fixture = TestBed.createComponent(TestChip);
2523
testChip = fixture.debugElement.componentInstance;
2624
fixture.detectChanges();
@@ -30,14 +28,14 @@ describe('Chip Remove', () => {
3028
}));
3129

3230
describe('basic behavior', () => {
33-
it('should applies the `mat-chip-remove` CSS class', () => {
34-
let hrefElement = chipNativeElement.querySelector('a')!;
31+
it('should apply the `mat-chip-remove` CSS class', () => {
32+
const hrefElement = chipNativeElement.querySelector('a')!;
3533

3634
expect(hrefElement.classList).toContain('mat-chip-remove');
3735
});
3836

39-
it('should emits (remove) on click', () => {
40-
let hrefElement = chipNativeElement.querySelector('a')!;
37+
it('should emit (remove) on click', () => {
38+
const hrefElement = chipNativeElement.querySelector('a')!;
4139

4240
testChip.removable = true;
4341
fixture.detectChanges();
@@ -48,6 +46,19 @@ describe('Chip Remove', () => {
4846

4947
expect(testChip.didRemove).toHaveBeenCalled();
5048
});
49+
50+
it('should prevent the default click action', () => {
51+
const hrefElement = chipNativeElement.querySelector('a')!;
52+
53+
testChip.removable = true;
54+
fixture.detectChanges();
55+
56+
const event = dispatchFakeEvent(hrefElement, 'click');
57+
fixture.detectChanges();
58+
59+
expect(event.defaultPrevented).toBe(true);
60+
});
61+
5162
});
5263
});
5364

src/lib/chips/chip.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,22 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes
308308
selector: '[matChipRemove]',
309309
host: {
310310
'class': 'mat-chip-remove',
311-
'(click)': '_handleClick()',
311+
'(click)': '_handleClick($event)',
312312
}
313313
})
314314
export class MatChipRemove {
315315
constructor(protected _parentChip: MatChip) {
316316
}
317317

318318
/** Calls the parent chip's public `remove()` method if applicable. */
319-
_handleClick(): void {
319+
_handleClick(event: MouseEvent): void {
320320
if (this._parentChip.removable) {
321321
this._parentChip.remove();
322+
323+
// Note: the parent chip does something similar, however since we're removing it,
324+
// its event handler will be unbound before it has had the chance to fire.
325+
event.preventDefault();
326+
event.stopPropagation();
322327
}
323328
}
324329
}

0 commit comments

Comments
 (0)