Skip to content

Commit 3e984c7

Browse files
authored
fix(drag-drop): defer resolving scrollable parents until first drag (#18918)
Currently we resolve a drop list's scrollable parents inside `ngAfterViewInit`, but this might be too early if the element is being projected. These changes move the logic to the first time the user starts dragging which should guarantee that the DOM structure has settled. Fixes #18737.
1 parent 262e2e4 commit 3e984c7

File tree

2 files changed

+19
-14
lines changed

2 files changed

+19
-14
lines changed

src/cdk/drag-drop/directives/drop-list.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
Directive,
1818
ChangeDetectorRef,
1919
SkipSelf,
20-
AfterContentInit,
2120
Inject,
2221
} from '@angular/core';
2322
import {Directionality} from '@angular/cdk/bidi';
@@ -59,10 +58,13 @@ export interface CdkDropListInternal extends CdkDropList {}
5958
'[class.cdk-drop-list-receiving]': '_dropListRef.isReceiving()',
6059
}
6160
})
62-
export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
61+
export class CdkDropList<T = any> implements OnDestroy {
6362
/** Emits when the list has been destroyed. */
6463
private _destroyed = new Subject<void>();
6564

65+
/** Whether the element's scrollable parents have been resolved. */
66+
private _scrollableParentsResolved: boolean;
67+
6668
/** Keeps track of the drop lists that are currently on the page. */
6769
private static _dropLists: CdkDropList[] = [];
6870

@@ -183,16 +185,6 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
183185
}
184186
}
185187

186-
ngAfterContentInit() {
187-
// @breaking-change 11.0.0 Remove null check for _scrollDispatcher once it's required.
188-
if (this._scrollDispatcher) {
189-
const scrollableParents = this._scrollDispatcher
190-
.getAncestorScrollContainers(this.element)
191-
.map(scrollable => scrollable.getElementRef().nativeElement);
192-
this._dropListRef.withScrollableParents(scrollableParents);
193-
}
194-
}
195-
196188
/** Registers an items with the drop list. */
197189
addItem(item: CdkDrag): void {
198190
this._unsortedItems.add(item);
@@ -321,6 +313,20 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
321313
});
322314
}
323315

316+
// Note that we resolve the scrollable parents here so that we delay the resolution
317+
// as long as possible, ensuring that the element is in its final place in the DOM.
318+
// @breaking-change 11.0.0 Remove null check for _scrollDispatcher once it's required.
319+
if (!this._scrollableParentsResolved && this._scrollDispatcher) {
320+
const scrollableParents = this._scrollDispatcher
321+
.getAncestorScrollContainers(this.element)
322+
.map(scrollable => scrollable.getElementRef().nativeElement);
323+
this._dropListRef.withScrollableParents(scrollableParents);
324+
325+
// Only do this once since it involves traversing the DOM and the parents
326+
// shouldn't be able to change without the drop list being destroyed.
327+
this._scrollableParentsResolved = true;
328+
}
329+
324330
ref.disabled = this.disabled;
325331
ref.lockAxis = this.lockAxis;
326332
ref.sortingDisabled = coerceBooleanProperty(this.sortingDisabled);

tools/public_api_guard/cdk/drag-drop.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export interface CdkDragStart<T = any> {
145145
source: CdkDrag<T>;
146146
}
147147

148-
export declare class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
148+
export declare class CdkDropList<T = any> implements OnDestroy {
149149
_dropListRef: DropListRef<CdkDropList<T>>;
150150
autoScrollDisabled: boolean;
151151
connectedTo: (CdkDropList | string)[] | CdkDropList | string;
@@ -171,7 +171,6 @@ export declare class CdkDropList<T = any> implements AfterContentInit, OnDestroy
171171
exit(item: CdkDrag): void;
172172
getItemIndex(item: CdkDrag): number;
173173
getSortedItems(): CdkDrag[];
174-
ngAfterContentInit(): void;
175174
ngOnDestroy(): void;
176175
removeItem(item: CdkDrag): void;
177176
start(): void;

0 commit comments

Comments
 (0)