'Angular 8 & Angular Material: Drag Scrolling with CdkDropList item

I'm trying to provide scrolling while dragging a cdkDropList item. As of right now the page can't scroll without using the mousewheel to scroll. I was hoping to be able to just scroll through the page based on the dragging of the list item. After googling it looks like it wasn't possible until a few months ago?!

I found the following commit on the angular material repo: https://github.com/crisbeto/material2/commit/b4be85f6716a2d1a432ef7109aa06e7255324222

but haven't found any documentation on the angular material site. I was curious if anyone has implemented any auto drag scrolling on a CdkDropList element with Angular Material since this was released. I'm newer to angular. I've tried adding the cdkScrollable tag to the div but have been able to get the auto-scroll function to work while dragging any of the elements in the list.

Thoughts/advice?



Solution 1:[1]

From version 9.1.0, the auto scrolling is supported by setting cdkScrollable directive on the parent that should scroll.

So, for v9.1.0 and up, the following code should work:

<div style="height: 500px; overflow-y: auto" cdkScrollable>
  <div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
    <div class="example-box" *ngFor="let movie of movies" cdkDrag>{{movie}}</div>
  </div>
</div>

Stackblitz demo:

https://stackblitz.com/edit/angular-swaqkk-njehwg (uses Angular CDK v10.0.1)

https://stackblitz.com/edit/angular-swaqkk-tssfag (uses Angular CDK v13.3.6)

Update 2022-05-11


Also, I've posted a more complete answer, which includes more examples and also solutions for Angular8, at the following topic: Angular CDK - issue with scrolling and dragging element inside nested scrollable div

Solution 2:[2]

Just combining my research into an answer. Dig deeper into the D&D API for what exists.

  <div #boardWrapper class="board-wrapper" cdkScrollable>
    <!-- cdkDropListGroup when multiple droplists -->    
    <div #boardColumns class="board-columns" cdkDropListGroup>
      <!-- A drop list -->
      <div
        cdkDropList
        [cdkDropListAutoScrollDisabled]="false" <-- enable
        [cdkDropListAutoScrollStep]="35"        <-- speed
        [cdkDropListData]="data.arr"
        (cdkDropListDropped)="drop($event)"
      >
        <!-- A drag item -->
        <div
          cdkDrag
          [cdkDragData]="item.data"
          (cdkDragMoved)="onDragMoved($event)"
          (cdkDragStarted)="dragStarted($event)"
        >content</div>
      </div>
    </div>
  </div>

Solution 3:[3]

Note: cdkScrollable does not magically make anything scrollable. You have to build the subscription and action to handle the event.

Regarding cdkDropList, it will scroll if a child element contains an *ngFor with the items it is to loop over. Modified @andreivictor's answer to prove this: https://stackblitz.com/edit/angular-swaqkk-4iaqwc?file=src%2Fapp%2Fcdk-drag-drop-sorting-example.html

<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
    <div *ngFor="let movie of movies" >
    <ng-container *ngTemplateOutlet="Tmpl2; context:{ movieT: movie }">
    </ng-container>
</div>
<ng-template #Tmpl2 let-movieT="movieT">
    <div>
                <div class="example-box" cdkDrag>{{movieT}}</div>
    </div>
</ng-template>

Move the ngFor div into the template and rename {{movieT}} to {{movie}} and you'll see the scrolling stops. This is because the cdkDropList directive can no longer access the items inside another component. I don't know of any way to handle this scenario, but if you can avoid templates I'd imagine the scrolling should work as expected. It is also an issue if you are nesting lists. I could not get cdkDropListGroup attribute to work, though adding an id attribute and using the cdkDropListConnectedTo array attribute (found on the same link) works well.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Ben Racicot
Solution 3 Had To Ask