How to integrate Angular's material drag and drop with virtual scrolling?

点点圈 提交于 2020-05-26 15:09:18

问题


I'm trying to integrate Angular material's virtual scrolling with drag and drop, but for some reason when i'm trying to implement this it reverts the items and when i'm trying to drag and drop an element it doesn't work.

Here is a summary of the code

<cdk-virtual-scroll-viewport cdkDropList  itemSize="50" class="example-viewport">
  <div cdkDrag *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>

As you can see, I didn't do anything special, besides that I replaced *ngFor with cdkVirtualFor because the docs are telling me that:

*cdkVirtualFor replaces *ngFor inside of a <cdk-virtual-scroll-viewport>, supporting the exact same API as *ngFor.

I've attached here a stackblitz demo! So, how to integrate drag and drop with virtual scrolling?


回答1:


I was able to get drag and drop working inside of virtual scroll with Angular 8.

<cdk-virtual-scroll-viewport itemSize="10" class="viewport">
  <mat-chip-list
    class="mat-chip-list-stacked"
    cdkDropList
    [cdkDropListData]="items"
    (cdkDropListDropped)="drop($event)">
    <mat-chip *cdkVirtualFor="let item of items" cdkDrag>
      {{ item.name }}
    </mat-chip>
  </mat-chip-list>
</cdk-virtual-scroll-viewport>

For some reason, moveItemInArray did not fire off change detection in the *cdkVirtualFor like it did for *ngFor. So, I added this.auditItems = [...this.auditItems]; to my drop event and that seemed to fix it.

drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    this.items = [...this.items];
}



回答2:


I'm sry, but i think Angular materials cdkDrag does NOT work with virtual-scroll at the moment, see linked material issue .

Following the mentioned thread there is only one demo which seems to work, but the provided sources are sadly only available as compiled js not ts.

In fact you have to make the decision to work with angulars drag and drop via cdkDrag OR angulars scrolling via virtual scroll.




回答3:


So the thing is, the drop list is referencing the indexes of the rendered items. So this would only work if you add the start index of the currently rendered view to the dropped item from/to indexes, like so:

<cdk-virtual-scroll-viewport cdkDropList #virtualScroller 
  (cdkDropListDropped)="onItemDrop($event)"  itemSize="50" class="example-viewport">  
  <div cdkDrag *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>

And the typescript code would have:

@ViewChild('virtualScroller') virtualScroller: CdkVirtualScrollViewport;
...
onItemDrop(event: CdkDragDrop<FormViewOrderingItem>) {
    const vsStartIndex = this.virtualScroller.getRenderedRange().start;
    moveItemInArray(this.formViewOrdering, event.previousIndex + vsStartIndex, event.currentIndex + vsStartIndex);
}

For example, the event fired on drop when you move the item at index 10 to index 12 of the list when the rendered range is 2-20 will show {start: 8, end: 10} so when you add the rendered start index, it fixes the problem.

Hope this helps, it worked for me.




回答4:


If you are looking for something like shown in the below image, than you need to use the code of transferring items between the lists code. Check out this link https://material.angular.io/cdk/drag-drop/overview#transferring-items-between-lists

And make some quick tweaks in css as per your requirement, as I have made some change in css in the browser itself to obtain the below result show in image.

You can also make 3 columns or 4 columns. Let me know if you need me to provide you the code?



来源:https://stackoverflow.com/questions/53817105/how-to-integrate-angulars-material-drag-and-drop-with-virtual-scrolling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!