1212 Output ,
1313 Renderer2 ,
1414 ChangeDetectorRef ,
15- ContentChild ,
1615 ViewContainerRef ,
1716 AfterContentInit ,
18- TemplateRef
17+ TemplateRef ,
18+ ContentChildren ,
19+ QueryList
1920} from '@angular/core' ;
2021import { animationFrameScheduler , fromEvent , interval , Subject } from 'rxjs' ;
2122import { takeUntil , throttle } from 'rxjs/operators' ;
@@ -454,8 +455,8 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
454455 /**
455456 * @hidden
456457 */
457- @ContentChild ( IgxDragHandleDirective , { static : false } )
458- public dragHandle : IgxDragHandleDirective ;
458+ @ContentChildren ( IgxDragHandleDirective )
459+ public dragHandles : QueryList < IgxDragHandleDirective > ;
459460
460461 /**
461462 * @hidden
@@ -525,10 +526,11 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
525526 /**
526527 * @hidden
527528 */
528- public set ghostLeft ( val : number ) {
529+ public set ghostLeft ( pageX : number ) {
529530 requestAnimationFrame ( ( ) => {
530531 if ( this . dragGhost ) {
531- this . dragGhost . style . left = val + 'px' ;
532+ // If ghost host is defined it needs to be taken into account.
533+ this . dragGhost . style . left = ( pageX - this . _dragGhostHostX ) + 'px' ;
532534 }
533535 } ) ;
534536 }
@@ -537,16 +539,17 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
537539 * @hidden
538540 */
539541 public get ghostLeft ( ) {
540- return parseInt ( this . dragGhost . style . left , 10 ) ;
542+ return parseInt ( this . dragGhost . style . left , 10 ) + this . _dragGhostHostX ;
541543 }
542544
543545 /**
544546 * @hidden
545547 */
546- public set ghostTop ( val : number ) {
548+ public set ghostTop ( pageY : number ) {
547549 requestAnimationFrame ( ( ) => {
548550 if ( this . dragGhost ) {
549- this . dragGhost . style . top = val + 'px' ;
551+ // If ghost host is defined it needs to be taken into account.
552+ this . dragGhost . style . top = ( pageY - this . _dragGhostHostY ) + 'px' ;
550553 }
551554 } ) ;
552555 }
@@ -555,7 +558,7 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
555558 * @hidden
556559 */
557560 public get ghostTop ( ) {
558- return parseInt ( this . dragGhost . style . top , 10 ) ;
561+ return parseInt ( this . dragGhost . style . top , 10 ) + this . _dragGhostHostY ;
559562 }
560563
561564 /**
@@ -629,41 +632,47 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
629632 * @hidden
630633 */
631634 public ngAfterContentInit ( ) {
632- const targetElement = this . dragHandle ? this . dragHandle . element . nativeElement : this . element . nativeElement ;
633635 this . zone . runOutsideAngular ( ( ) => {
634- if ( this . pointerEventsEnabled ) {
635- fromEvent ( targetElement , 'pointerdown' ) . pipe ( takeUntil ( this . _destroy ) )
636- . subscribe ( ( res ) => this . onPointerDown ( res ) ) ;
637-
638- fromEvent ( targetElement , 'pointermove' ) . pipe (
639- throttle ( ( ) => interval ( 0 , animationFrameScheduler ) ) ,
640- takeUntil ( this . _destroy )
641- ) . subscribe ( ( res ) => this . onPointerMove ( res ) ) ;
642-
643- fromEvent ( targetElement , 'pointerup' ) . pipe ( takeUntil ( this . _destroy ) )
644- . subscribe ( ( res ) => this . onPointerUp ( res ) ) ;
645-
646- if ( ! this . renderGhost ) {
647- // Do not bind `lostpointercapture` to the target, because we will bind it on the ghost later.
648- fromEvent ( targetElement , 'lostpointercapture' ) . pipe ( takeUntil ( this . _destroy ) )
649- . subscribe ( ( res ) => this . onPointerLost ( res ) ) ;
636+ const targetElements = this . dragHandles && this . dragHandles . length ?
637+ this . dragHandles . map ( ( item ) => item . element . nativeElement ) : [ this . element . nativeElement ] ;
638+ targetElements . forEach ( ( element ) => {
639+ if ( this . pointerEventsEnabled ) {
640+ fromEvent ( element , 'pointerdown' ) . pipe ( takeUntil ( this . _destroy ) )
641+ . subscribe ( ( res ) => this . onPointerDown ( res ) ) ;
642+
643+ fromEvent ( element , 'pointermove' ) . pipe (
644+ throttle ( ( ) => interval ( 0 , animationFrameScheduler ) ) ,
645+ takeUntil ( this . _destroy )
646+ ) . subscribe ( ( res ) => this . onPointerMove ( res ) ) ;
647+
648+ fromEvent ( element , 'pointerup' ) . pipe ( takeUntil ( this . _destroy ) )
649+ . subscribe ( ( res ) => this . onPointerUp ( res ) ) ;
650+
651+ if ( ! this . renderGhost ) {
652+ // Do not bind `lostpointercapture` to the target, because we will bind it on the ghost later.
653+ fromEvent ( element , 'lostpointercapture' ) . pipe ( takeUntil ( this . _destroy ) )
654+ . subscribe ( ( res ) => this . onPointerLost ( res ) ) ;
655+ }
656+ } else if ( this . touchEventsEnabled ) {
657+ fromEvent ( element , 'touchstart' ) . pipe ( takeUntil ( this . _destroy ) )
658+ . subscribe ( ( res ) => this . onPointerDown ( res ) ) ;
659+ } else {
660+ // We don't have pointer events and touch events. Use then mouse events.
661+ fromEvent ( element , 'mousedown' ) . pipe ( takeUntil ( this . _destroy ) )
662+ . subscribe ( ( res ) => this . onPointerDown ( res ) ) ;
650663 }
651- } else if ( this . touchEventsEnabled ) {
652- fromEvent ( targetElement , 'touchstart' ) . pipe ( takeUntil ( this . _destroy ) )
653- . subscribe ( ( res ) => this . onPointerDown ( res ) ) ;
664+ } ) ;
654665
666+ // We should bind to document events only once when there are no pointer events.
667+ if ( ! this . pointerEventsEnabled && this . touchEventsEnabled ) {
655668 fromEvent ( document . defaultView , 'touchmove' ) . pipe (
656669 throttle ( ( ) => interval ( 0 , animationFrameScheduler ) ) ,
657670 takeUntil ( this . _destroy )
658671 ) . subscribe ( ( res ) => this . onPointerMove ( res ) ) ;
659672
660673 fromEvent ( document . defaultView , 'touchend' ) . pipe ( takeUntil ( this . _destroy ) )
661674 . subscribe ( ( res ) => this . onPointerUp ( res ) ) ;
662- } else {
663- // We don't have pointer events and touch events. Use then mouse events.
664- fromEvent ( targetElement , 'mousedown' ) . pipe ( takeUntil ( this . _destroy ) )
665- . subscribe ( ( res ) => this . onPointerDown ( res ) ) ;
666-
675+ } else if ( ! this . pointerEventsEnabled ) {
667676 fromEvent ( document . defaultView , 'mousemove' ) . pipe (
668677 throttle ( ( ) => interval ( 0 , animationFrameScheduler ) ) ,
669678 takeUntil ( this . _destroy )
@@ -727,7 +736,8 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
727736 this . _pointerDownId = event . pointerId ;
728737
729738 // Set pointer capture so we detect pointermove even if mouse is out of bounds until dragGhost is created.
730- const targetElement = this . dragHandle ? this . dragHandle . element . nativeElement : this . element . nativeElement ;
739+ const handleFound = this . dragHandles . find ( handle => handle . element . nativeElement === event . target ) ;
740+ const targetElement = handleFound ? handleFound . element . nativeElement : this . element . nativeElement ;
731741 if ( this . pointerEventsEnabled ) {
732742 targetElement . setPointerCapture ( this . _pointerDownId ) ;
733743 } else {
@@ -749,26 +759,24 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
749759 this . _startY = event . touches [ 0 ] . pageY ;
750760 }
751761
752- let ghostOffsetX ;
753762 if ( this . ghostOffsetX !== undefined ) {
754- ghostOffsetX = this . ghostOffsetX ;
763+ this . _ghostOffsetX = this . ghostOffsetX ;
755764 } else {
756765 const marginLeft = parseInt ( document . defaultView . getComputedStyle ( this . element . nativeElement ) [ 'margin-left' ] , 10 ) ;
757- ghostOffsetX = this . element . nativeElement . getBoundingClientRect ( ) . left + this . getWindowScrollLeft ( ) - marginLeft -
766+ this . _ghostOffsetX = this . element . nativeElement . getBoundingClientRect ( ) . left + this . getWindowScrollLeft ( ) - marginLeft -
758767 this . _startX ;
759768 }
760769
761- let ghostOffsetY ;
762770 if ( this . ghostOffsetY !== undefined ) {
763- ghostOffsetY = this . ghostOffsetY ;
771+ this . _ghostOffsetY = this . ghostOffsetY ;
764772 } else {
765773 const marginTop = parseInt ( document . defaultView . getComputedStyle ( this . element . nativeElement ) [ 'margin-top' ] , 10 ) ;
766- ghostOffsetY = this . element . nativeElement . getBoundingClientRect ( ) . top + this . getWindowScrollTop ( ) - marginTop -
774+ this . _ghostOffsetY = this . element . nativeElement . getBoundingClientRect ( ) . top + this . getWindowScrollTop ( ) - marginTop -
767775 this . _startY ;
768776 }
769777
770- this . _ghostStartX = this . _startX + ghostOffsetX ;
771- this . _ghostStartY = this . _startY + ghostOffsetY ;
778+ this . _ghostStartX = this . _startX + this . _ghostOffsetX ;
779+ this . _ghostStartY = this . _startY + this . _ghostOffsetY ;
772780 this . _lastX = this . _startX ;
773781 this . _lastY = this . _startY ;
774782 }
@@ -822,11 +830,13 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
822830 }
823831
824832 if ( this . renderGhost ) {
825- this . ghostLeft = this . _ghostStartX + totalMovedX - this . _dragGhostHostX ;
826- this . ghostTop = this . _ghostStartY + totalMovedY - this . _dragGhostHostY ;
833+ this . ghostLeft = this . _ghostStartX + totalMovedX ;
834+ this . ghostTop = this . _ghostStartY + totalMovedY ;
827835 } else {
828- const translateX = this . getTransformX ( this . element . nativeElement ) + ( pageX - this . _lastX ) ;
829- const translateY = this . getTransformY ( this . element . nativeElement ) + ( pageY - this . _lastY ) ;
836+ const lastMovedX = pageX - this . _lastX ;
837+ const lastMovedY = pageY - this . _lastY ;
838+ const translateX = this . getTransformX ( this . element . nativeElement ) + lastMovedX ;
839+ const translateY = this . getTransformY ( this . element . nativeElement ) + lastMovedY ;
830840 this . setTransformXY ( translateX , translateY ) ;
831841 }
832842
@@ -943,8 +953,8 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
943953
944954 this . dragGhost . style . transitionDuration = '0.0s' ;
945955 this . dragGhost . style . position = 'absolute' ;
946- this . dragGhost . style . left = ( this . _ghostStartX + totalMovedX ) - this . _dragGhostHostX + 'px' ;
947- this . dragGhost . style . top = ( this . _ghostStartY + totalMovedY ) - this . _dragGhostHostY + 'px' ;
956+ this . ghostLeft = this . _ghostStartX + totalMovedX ;
957+ this . ghostTop = this . _ghostStartY + totalMovedY ;
948958
949959 if ( this . ghostImageClass ) {
950960 this . renderer . addClass ( this . dragGhost , this . ghostImageClass ) ;
@@ -1007,11 +1017,9 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy {
10071017 originalEvent : originalEvent
10081018 } ;
10091019
1010- this . zone . run ( ( ) => {
1011- this . dragMove . emit ( {
1012- originalEvent : originalEvent ,
1013- owner : this
1014- } ) ;
1020+ this . dragMove . emit ( {
1021+ originalEvent : originalEvent ,
1022+ owner : this
10151023 } ) ;
10161024
10171025 const elementsFromPoint = this . getElementsAtPoint ( pageX , pageY ) ;
0 commit comments