@@ -20,6 +20,8 @@ import {
20
20
EventEmitter ,
21
21
ViewContainerRef ,
22
22
EmbeddedViewRef ,
23
+ ContentChildren ,
24
+ QueryList ,
23
25
} from '@angular/core' ;
24
26
import { CdkDragHandle } from './drag-handle' ;
25
27
import { DOCUMENT } from '@angular/platform-browser' ;
@@ -42,6 +44,8 @@ const activeEventOptions = supportsPassiveEventListeners() ? {passive: false} :
42
44
exportAs : 'cdkDrag' ,
43
45
host : {
44
46
'class' : 'cdk-drag' ,
47
+ '(mousedown)' : '_startDragging($event)' ,
48
+ '(touchstart)' : '_startDragging($event)' ,
45
49
}
46
50
} )
47
51
export class CdkDrag implements AfterContentInit , OnDestroy {
@@ -88,8 +92,8 @@ export class CdkDrag implements AfterContentInit, OnDestroy {
88
92
/** Cached scroll position on the page when the element was picked up. */
89
93
private _scrollPosition : { top : number , left : number } ;
90
94
91
- /** Element that can be used to drag the draggable item. */
92
- @ContentChild ( CdkDragHandle ) _handle : CdkDragHandle ;
95
+ /** Elements that can be used to drag the draggable item. */
96
+ @ContentChildren ( CdkDragHandle ) _handles : QueryList < CdkDragHandle > ;
93
97
94
98
/** Element that will be used as a template to create the draggable item's preview. */
95
99
@ContentChild ( CdkDragPreview ) _previewTemplate : CdkDragPreview ;
@@ -135,11 +139,6 @@ export class CdkDrag implements AfterContentInit, OnDestroy {
135
139
}
136
140
137
141
ngAfterContentInit ( ) {
138
- // TODO: doesn't handle (pun intended) the handle being destroyed
139
- const dragElement = ( this . _handle ? this . _handle . element : this . element ) . nativeElement ;
140
- dragElement . addEventListener ( 'mousedown' , this . _pointerDown ) ;
141
- dragElement . addEventListener ( 'touchstart' , this . _pointerDown ) ;
142
-
143
142
// WebKit won't preventDefault on a dynamically-added `touchmove` listener, which means that
144
143
// we need to add one ahead of time. See https://bugs.webkit.org/show_bug.cgi?id=184250.
145
144
// TODO: move into a central registry.
@@ -162,8 +161,27 @@ export class CdkDrag implements AfterContentInit, OnDestroy {
162
161
}
163
162
}
164
163
164
+ /** Starts the dragging sequence. */
165
+ _startDragging ( event : MouseEvent | TouchEvent ) {
166
+ // Delegate the event based on whether it started from a handle or the element itself.
167
+ if ( this . _handles . length ) {
168
+ const targetHandle = this . _handles . find ( handle => {
169
+ const element = handle . element . nativeElement ;
170
+ const target = event . target ;
171
+ return ! ! target && ( target === element || element . contains ( target as HTMLElement ) ) ;
172
+ } ) ;
173
+
174
+ if ( targetHandle ) {
175
+ this . _pointerDown ( targetHandle . element , event ) ;
176
+ }
177
+ } else {
178
+ this . _pointerDown ( this . element , event ) ;
179
+ }
180
+ }
181
+
165
182
/** Handler for when the pointer is pressed down on the element or the handle. */
166
- private _pointerDown = ( event : MouseEvent | TouchEvent ) => {
183
+ private _pointerDown = ( referenceElement : ElementRef < HTMLElement > ,
184
+ event : MouseEvent | TouchEvent ) => {
167
185
if ( this . _isDragging ) {
168
186
return ;
169
187
}
@@ -175,7 +193,7 @@ export class CdkDrag implements AfterContentInit, OnDestroy {
175
193
// If we have a custom preview template, the element won't be visible anyway so we avoid the
176
194
// extra `getBoundingClientRect` calls and just move the preview next to the cursor.
177
195
this . _pickupPositionInElement = this . _previewTemplate ? { x : 0 , y : 0 } :
178
- this . _getPointerPositionInElement ( event ) ;
196
+ this . _getPointerPositionInElement ( referenceElement , event ) ;
179
197
this . _pickupPositionOnPage = this . _getPointerPositionOnPage ( event ) ;
180
198
this . _registerMoveListeners ( event ) ;
181
199
@@ -371,11 +389,13 @@ export class CdkDrag implements AfterContentInit, OnDestroy {
371
389
372
390
/**
373
391
* Figures out the coordinates at which an element was picked up.
392
+ * @param referenceElement Element that initiated the dragging.
374
393
* @param event Event that initiated the dragging.
375
394
*/
376
- private _getPointerPositionInElement ( event : MouseEvent | TouchEvent ) : Point {
395
+ private _getPointerPositionInElement ( referenceElement : ElementRef < HTMLElement > ,
396
+ event : MouseEvent | TouchEvent ) : Point {
377
397
const elementRect = this . element . nativeElement . getBoundingClientRect ( ) ;
378
- const handleElement = this . _handle ? this . _handle . element . nativeElement : null ;
398
+ const handleElement = referenceElement === this . element ? null : referenceElement . nativeElement ;
379
399
const referenceRect = handleElement ? handleElement . getBoundingClientRect ( ) : elementRect ;
380
400
const x = this . _isTouchEvent ( event ) ?
381
401
event . targetTouches [ 0 ] . pageX - referenceRect . left - this . _scrollPosition . left :
0 commit comments