Angular 8 & Angular Material: Drag Scrolling with CdkDropList item
Asked Answered
S

3

8

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?

Stamps answered 12/12, 2019 at 1:41 Comment(2)
You can try with event listners like when the user is drag to the near bottom of the scrollable list then scroll the list to bottom if the user drags an item on near top of the scrollable list then scroll to top.Denney
I guess apparently it should automatically work for the scroll. I guess theres some sort of constraint with fixed-height/width layouts/containers, I believe is what I found out.Stamps
C
14

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

Cato answered 5/11, 2020 at 6:33 Comment(2)
having a fixed height, either in px or % is required for this to work.Conterminous
Default speed doesnt work well. Don't forget the API details for cdkDropList [cdkDropListAutoScrollDisabled]="false" [cdkDropListAutoScrollStep]="35"Kirkwall
K
3

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>
Kirkwall answered 8/3, 2022 at 21:19 Comment(2)
Is [cdkDropListAutoScrollDisabled]="false" really necesarry? Looking at the source code, it doesn't seem that auto scroll is disabled by default. Also the following stackblitz works well: stackblitz.com/edit/angular-swaqkk-tssfag.Cato
@Cato probably correct. I am using false in a project for unrelated reasons.Kirkwall
S
0

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.

Seroka answered 9/6, 2021 at 14:32 Comment(5)
it does make it scroll, as long as the the element that has the cdkScrollable has a fixed height.Conterminous
Can you prove this? I have found no correlation in testing and removing cdkScrollable or the styles from the original answer's stackblitz has no effect on scrolling.Seroka
When I implemented this there is not "scroll event handlers" just cdkScrollable - ibb.co/QF47N79 - just like the other answer says. It did not work until I set a height to the container where I wanted the scrollsConterminous
I'm not understanding. The only height in my link is min-height: 60px; so maybe you're doing something different?Seroka
is been 2 years now, imposible to replicate it nowConterminous

© 2022 - 2024 — McMap. All rights reserved.