Search code examples
javascriptangularangular-cdkangular-cdk-drag-drop

Angular CdkDrag element loses event listener after transferring item to a new list


I am using Angular's Drag Drop CDK to transfer items between two lists. One specific functionality I need is to be able to listen to the cdkDrag element's started Subject provided by the component API. However, after I transfer the item to a new list, I lose the event listener.


Example code here: https://stackblitz.com/edit/angular-m8lcqp

When moving an element such as Fall Asleep to the Done list, I log started dragging to the console. But if you try to move that element back to the first list, the event is not fired. What am I doing incorrectly?


To subscribe to the started event, I use ViewChildren to get a QueryList of cdkDrag. Within an ngAfterViewInit(), I loop through these drag elements and subscribe to the started event:

ngAfterViewInit() {
  this.dragItems.forEach((drag) => {
    drag.started.subscribe((element) => {
      console.log('started dragging');
    })
  })
}

What is the correct way to track this event? Do I need to detect changes on the page and then re-loop through and resubscribe since the cdkDrag element is now in a different list? Thank you!


Solution

  • I'm afraid you're right. Once you moved an item from one list to the other, it's attached to a new CdkDrag instance of the other list so your subscription stops receiving emissions. Worse than that, it seems to be a potential source of memory leaking, as the subscription is never torn down explicitly.

    Your best shot is adding a listener directly on the draggable element:

    <div *ngFor="let item of done"
         (cdkDragStarted)="_dragStartedHandler($event)" 
         cdkDrag>{{item}}</div>
    
    _dragStartedHandler(element: CdkDragStart) {
      console.log("started dragging");
    }