I've searched for this issue in the Angular components' official Github repository and I have found the following topics:
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:
- 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
- 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