Skip to content

Commit e6db9d3

Browse files
committed
fix(drag-drop): stop dragging sequence on touchcancel
Adds handling for the `touchcancel` event to the the `DragDropRegistry`.
1 parent fe26614 commit e6db9d3

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

src/cdk/drag-drop/drag-drop-registry.spec.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ describe('DragDropRegistry', () => {
6969
const subscription = registry.pointerMove.subscribe(spy);
7070

7171
registry.startDragging(testComponent.dragItems.first, createMouseEvent('mousedown'));
72-
dispatchMouseEvent(document, 'mousemove');
72+
const event = dispatchMouseEvent(document, 'mousemove');
7373

74-
expect(spy).toHaveBeenCalled();
74+
expect(spy).toHaveBeenCalledWith(event);
7575

7676
subscription.unsubscribe();
7777
});
@@ -82,9 +82,9 @@ describe('DragDropRegistry', () => {
8282

8383
registry.startDragging(testComponent.dragItems.first,
8484
createTouchEvent('touchstart') as TouchEvent);
85-
dispatchTouchEvent(document, 'touchmove');
85+
const event = dispatchTouchEvent(document, 'touchmove');
8686

87-
expect(spy).toHaveBeenCalled();
87+
expect(spy).toHaveBeenCalledWith(event);
8888

8989
subscription.unsubscribe();
9090
});
@@ -107,9 +107,9 @@ describe('DragDropRegistry', () => {
107107
const subscription = registry.pointerUp.subscribe(spy);
108108

109109
registry.startDragging(testComponent.dragItems.first, createMouseEvent('mousedown'));
110-
dispatchMouseEvent(document, 'mouseup');
110+
const event = dispatchMouseEvent(document, 'mouseup');
111111

112-
expect(spy).toHaveBeenCalled();
112+
expect(spy).toHaveBeenCalledWith(event);
113113

114114
subscription.unsubscribe();
115115
});
@@ -120,9 +120,22 @@ describe('DragDropRegistry', () => {
120120

121121
registry.startDragging(testComponent.dragItems.first,
122122
createTouchEvent('touchstart') as TouchEvent);
123-
dispatchTouchEvent(document, 'touchend');
123+
const event = dispatchTouchEvent(document, 'touchend');
124124

125-
expect(spy).toHaveBeenCalled();
125+
expect(spy).toHaveBeenCalledWith(event);
126+
127+
subscription.unsubscribe();
128+
});
129+
130+
it('should dispatch `touchcancel` events if the drag was interrupted', () => {
131+
const spy = jasmine.createSpy('pointerUp spy');
132+
const subscription = registry.pointerUp.subscribe(spy);
133+
134+
registry.startDragging(testComponent.dragItems.first,
135+
createTouchEvent('touchstart') as TouchEvent);
136+
const event = dispatchTouchEvent(document, 'touchcancel');
137+
138+
expect(spy).toHaveBeenCalledWith(event);
126139

127140
subscription.unsubscribe();
128141
});

src/cdk/drag-drop/drag-drop-registry.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
126126
const isTouchEvent = event.type.startsWith('touch');
127127
const moveEvent = isTouchEvent ? 'touchmove' : 'mousemove';
128128
const upEvent = isTouchEvent ? 'touchend' : 'mouseup';
129+
const upConfig = {
130+
handler: (e: Event) => this.pointerUp.next(e as TouchEvent | MouseEvent),
131+
options: true
132+
};
129133

130134
// We explicitly bind __active__ listeners here, because newer browsers will default to
131135
// passive ones for `mousemove` and `touchmove`. The events need to be active, because we
@@ -151,6 +155,13 @@ export class DragDropRegistry<I, C extends {id: string}> implements OnDestroy {
151155
options: activeCapturingEventOptions
152156
});
153157

158+
if (isTouchEvent) {
159+
// Treat `touchcancel` events the same as `touchend`. `touchcancel` will fire for cases
160+
// like an OS-level event interrupting the touch sequence or the user putting too many
161+
// finger on the screen at the same time.
162+
this._globalListeners.set('touchcancel', upConfig);
163+
}
164+
154165
this._ngZone.runOutsideAngular(() => {
155166
this._globalListeners.forEach((config, name) => {
156167
this._document.addEventListener(name, config.handler, config.options);

0 commit comments

Comments
 (0)