Ryware / ngx-drag-and-drop-lists

Angular drag and drop component for lists
MIT License
49 stars 40 forks source link

[dndMoved] being called from another component when item dropped (unrelated components) #115

Open Francisco-RP opened 1 year ago

Francisco-RP commented 1 year ago

I just encountered an interesting edge case that I'm going to note here just in case someone else runs into this.

I have 2 instances of [dndLlist] on one page in completely separate parts of the app, they are not nested within each other. They both contain the same list of objects but both the array and its items (objects) are cloned, so they are not the same references/pointers. I was encountering an issue where the (dndMoved) event listener was being triggered in both components instead of only the one currently being dragged.

I think I figured out why this is happening. In dnd-list.ts line 13 you are exporting dropAccepted which is a singleton. All imports and instances of [dndLists] use this one instance

export const dropAccepted: Subject<any> = new Subject();

In dnd-draggable.ts line 51 you are subscribing to dropAccepted. If I drop in one place, all instances of [dndDraggable] on the entire page will get this subscription triggered. In order to only call the events on the current component, you're doing an object equality check using JSON.stringify, dnd-draggable.ts line 53

   if (JSON.stringify(this.dndObject) === JSON.stringify(item)) {

The edge case for me was that these objects in both of my separate lists were exactly the same when checked using this type of JSON.stringify equality check since they were clones of each other

My simple solution is to use an extra property on the objects and set them to different values depending on which list they are in (in my case it was just a simple true/false)

I think the library can handle this edge case though. Maybe each instance of [dndList] has a id that gets set in the constructor and checked during the handleDrop. It can be part of the event.dataTransfer. Maybe dndList can check if the element has an id first and use that, if not it can generate one (which can simply be done without third part libraries being involved)

NOTE This issue can happen for all of these events listed here:

let cb: object = { copy: 'dndCopied', link: 'dndLinked', move: 'dndMoved', none: 'dndCanceled' };

This only happened for me with dndMoved because I'm only using dndMoved