3
votes

I'm working on some project with Angular Material Drag And Drop. I've made a simplified example on StackBlitz https://stackblitz.com/edit/drag-and-drop-with-pipe?file=src%2Fapp%2Fdispatch.component.ts

A list of pets and a list of boxes. You can drag the pets and drop them in a zone of the boxes list, so each box can contain X pets.

This works ! But I want to add a custom pipe to dynamically filter each list e.g. only displaying cats, or pets named Rex

I'm pretty new to Angular and JS/TS and I found this piece of code to make my custom pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'listFilter'
})
export class ListFilterPipe implements PipeTransform {

  transform(items: any[], searchText: string): any[] {
    if (!items) return [];
    if (!searchText) return items;

    return items.filter(item => {
      return Object.keys(item).some(key => {
        return String(item[key]).toLowerCase().includes(searchText.toLowerCase());
      });
    });
   }

}

I also use the example given in Material's Documentation for the Drag And Drop event

drop(event: CdkDragDrop<string[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else {
      transferArrayItem(event.previousContainer.data,
                        event.container.data,
                        event.previousIndex,
                        event.currentIndex);
    }
  }


And this works ! But no !

Without filter, when a pet is put into a box, it disappears from the pets list and appears into the box. It's ok !

But with filter (e.g. Name = Rex which index is 1) when I drag & drop the pet, the wrong one is put in the box (actually it's "Stella" which is at index 0 but is hidden) and Rex still appears in the pets list.

I hope my explanations are clear (sorry for my english) but you can try it on this stackblitz mentioned above : if you filter the pets and do a Drag & Drop, the wrong pet is moved.

This gif illustrates the issue :

enter image description here

It seems that the drop event takes the index of the unfiltered list and I don't have a clue how to fix it.

Thanks a lot.

1
Did you ever solve this?tunneling
Yes Sort of. I had to use a workaround. I let the pipe solution down for a home-made filter function. I now use 2 lists, a "pristine" one and a filtered copy with arry.filter(). The filtered list is now displayed, every item that doesn't fit to the filter is not hidden but just don't exist, so the indexes are correct And at every drag & Drop, the "pristine" list is updated. Kinda dirty but just good enough for meDavid Klein

1 Answers

0
votes

Hello I have faced the same issue and did a lot of research and I have achieved this, in this scenario use can use touchend event and mousedown event on that card and pass the current item and the array

The below code is used for mobile touch screen touchend

<div*ngFor="let item of array">
<div (touchend)="dragTouchEndEvent(array,item)">
</div>
</div>

this code is used for desktop browsers (mousedown)

<div*ngFor="let item of array">
    <div (mousedown)="dragTouchEndEvent(array,item)">
    </div>
    </div>

declare a variable

 previousIndex:number;

so in ts file of that component add this

 dragTouchEndEvent(itemArray, item) {
    this.previousIndex = itemArray.findIndex(e => e === item);
  }

now replace event.previousIndex with this.previousIndex and clear your search filter

 someMethod(event: CdkDragDrop<any>){
        if (event.previousContainer === event.container) {
              moveItemInArray(event.container.data, this.previousIndex, event.currentIndex);
            } else {
              transferArrayItem(event.previousContainer.data,
                event.container.data,
                this.previousIndex,
                event.currentIndex);
    
            }
//clear your search filter here
}