Angular CDK - issue with scrolling and dragging element inside nested scrollable div

和自甴很熟 提交于 2020-12-29 05:50:12

问题


Prerequisite: cdk draggable elements inside a nested scrollable div (see the example https://stackblitz.com/edit/angular-7y19nm?file=app/cdk-drag-drop-sorting-example.html)

How to reproduce: Start dragging an item -> scroll the page -> drag item a bit more when not scrolling

Effect: item placeholder stays in wrong place and it's basically impossible to drag item anywhere outside the viewport.

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

回答1:


I've searched for this issue in the Angular components' official Github repository and I have found the following topics:

  • https://github.com/angular/components/issues/13588

  • https://github.com/angular/components/issues/16535

There are different solutions depending on the version that you use: Angular 9+ (works also with Angular 10) or Angular 8:

Angular 9+ (works also Angular 10)

From version 9.1.0, the scrolling of the parent element is supported by setting the cdkScrollable directive to it.

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

<div style="height: 100vh; 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-yjiz7r (uses v10.0.1)

https://stackblitz.com/edit/angular-vszdat (uses v9.2.4)


Angular 8

From version 8.1.0, the scrolling was enabled, but only for the cdkDropList itself or the viewport (for performance reasons). So there are two solutions available:

  1. We can set the fixed height and the overflow: scroll to the cdkDropList element:
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)" style="height: 100vh; overflow-y: auto">
  <div class="example-box" *ngFor="let movie of movies" cdkDrag>{{movie}} 
  </div>
</div>

Stackblitz demo:

https://stackblitz.com/edit/angular-avezy6

  1. If we can't make the cdkDropList scrollable and there is a parent element that should scroll (like the situation in the question), I've adapted a solution found here (https://github.com/angular/components/issues/16677#issuecomment-562625427): we can use a custom directive cdkDropListScrollContainer, that will be set on the cdkDrag elements. This directive will take as a Input the reference to the parent element that should scroll:
<div class="example-container" style="height: 500px; overflow-y: auto" #scrollContainer>
  <div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
    <div
      class="example-box"
      *ngFor="let movie of movies"
      cdkDrag
      [cdkDropListScrollContainer]="scrollContainer">
      {{movie}}
    </div>
  </div>
</div>

The code for the directive is:

import { Directive, Input, ElementRef } from "@angular/core";
import { CdkDrag } from "@angular/cdk/drag-drop";

@Directive({
  selector: "[cdkDropListScrollContainer]"
})
export class CdkDropListScrollContainerDirective {
  @Input("cdkDropListScrollContainer") scrollContainer: HTMLElement;
  originalElement: ElementRef<HTMLElement>;

  constructor(cdkDrag: CdkDrag) {

    cdkDrag._dragRef.beforeStarted.subscribe(() => {
      const cdkDropList = cdkDrag.dropContainer;
      if (!this.originalElement) {
        this.originalElement = cdkDropList.element;
      }

      if (this.scrollContainer) {
        const element = this.scrollContainer;
        cdkDropList._dropListRef.element = element;
        cdkDropList.element = new ElementRef<HTMLElement>(element);
      } else {
        cdkDropList._dropListRef.element = cdkDropList.element.nativeElement;
        cdkDropList.element = this.originalElement;
      }
    });

  }
}

Stackblitz demo: https://stackblitz.com/edit/angular-jkuqhg



来源:https://stackoverflow.com/questions/57755127/angular-cdk-issue-with-scrolling-and-dragging-element-inside-nested-scrollable

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