Skip to content

Commit 3660530

Browse files
authored
fix(material/chips): prevent default behavior on remove button (#24722)
Adds a `preventDefault` call to the `click` handlers of the chip remove icon in order to avoid things like form submissions and link navigations. Fixes #24436.
1 parent 9243266 commit 3660530

File tree

4 files changed

+21
-2
lines changed

4 files changed

+21
-2
lines changed

src/material-experimental/mdc-chips/chip-action.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,12 @@ export class MatChipAction
8888
/** Whether the action is interactive. */
8989
@Input() isInteractive = true;
9090

91-
_handleClick(_event: MouseEvent) {
91+
_handleClick(event: MouseEvent) {
9292
// Usually these events can't happen while the chip is disabled since the browser won't
9393
// allow them which is what MDC seems to rely on, however the event can be faked in tests.
9494
if (!this.disabled && this.isInteractive) {
9595
this._foundation.handleClick();
96+
event.preventDefault();
9697
}
9798
}
9899

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {Component} from '@angular/core';
22
import {waitForAsync, ComponentFixture, TestBed, fakeAsync, flush} from '@angular/core/testing';
3-
import {dispatchKeyboardEvent} from '@angular/cdk/testing/private';
3+
import {dispatchKeyboardEvent, dispatchMouseEvent} from '@angular/cdk/testing/private';
44
import {By} from '@angular/platform-browser';
55
import {SPACE, ENTER} from '@angular/cdk/keycodes';
66
import {MDCChipAnimation, MDCChipCssClasses} from '@material/chips/chip';
@@ -121,6 +121,14 @@ describe('MDC-based Chip Remove', () => {
121121
const buttonElement = chipNativeElement.querySelector('.mdc-evolution-chip__icon--trailing')!;
122122
expect(buttonElement.classList.contains('mat-mdc-focus-indicator')).toBe(true);
123123
}));
124+
125+
it('should prevent the default click action', fakeAsync(() => {
126+
const buttonElement = chipNativeElement.querySelector('button')!;
127+
const event = dispatchMouseEvent(buttonElement, 'click');
128+
triggerRemoveSequence();
129+
130+
expect(event.defaultPrevented).toBe(true);
131+
}));
124132
});
125133
});
126134

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {Component, DebugElement} from '@angular/core';
22
import {By} from '@angular/platform-browser';
33
import {waitForAsync, ComponentFixture, TestBed} from '@angular/core/testing';
44
import {MatChip, MatChipsModule} from './index';
5+
import {dispatchMouseEvent} from '@angular/cdk/testing/private';
56

67
describe('Chip Remove', () => {
78
let fixture: ComponentFixture<TestChip>;
@@ -74,6 +75,14 @@ describe('Chip Remove', () => {
7475

7576
expect(testChip.didRemove).not.toHaveBeenCalled();
7677
});
78+
79+
it('should prevent the default click action', () => {
80+
const buttonElement = chipNativeElement.querySelector('button')!;
81+
const event = dispatchMouseEvent(buttonElement, 'click');
82+
fixture.detectChanges();
83+
84+
expect(event.defaultPrevented).toBe(true);
85+
});
7786
});
7887
});
7988

src/material/chips/chip.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,5 +500,6 @@ export class MatChipRemove {
500500
// the parent click listener of the `MatChip` would prevent propagation, but it can happen
501501
// that the chip is being removed before the event bubbles up.
502502
event.stopPropagation();
503+
event.preventDefault();
503504
}
504505
}

0 commit comments

Comments
 (0)