Skip to content

Commit 37be099

Browse files
authored
fix(cdk/drag-drop): error if preview dimensions are accessed too early (#24498)
Fixes a null pointer exception that can happen if the page is scrolled before the user has scrolled the minimum distance. The problem was that we were expecting for the dimensions to be defined by the time the user has had the chance to scroll, but in some cases that can be circumvented. These changes move the measurement to a getter method so that they're guaranteed to be available when they are requested. Fixes #24497.
1 parent a8ec63c commit 37be099

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

src/cdk/drag-drop/drag-ref.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export class DragRef<T = any> {
240240
/** Whether the native dragging interactions have been enabled on the root element. */
241241
private _nativeInteractionsEnabled = true;
242242

243-
/** Cached dimensions of the preview element. */
243+
/** Cached dimensions of the preview element. Should be read via `_getPreviewRect`. */
244244
private _previewRect?: ClientRect;
245245

246246
/** Cached dimensions of the boundary element. */
@@ -686,15 +686,6 @@ export class DragRef<T = any> {
686686
return;
687687
}
688688

689-
// We only need the preview dimensions if we have a boundary element.
690-
if (this._boundaryElement) {
691-
// Cache the preview element rect if we haven't cached it already or if
692-
// we cached it too early before the element dimensions were computed.
693-
if (!this._previewRect || (!this._previewRect.width && !this._previewRect.height)) {
694-
this._previewRect = (this._preview || this._rootElement).getBoundingClientRect();
695-
}
696-
}
697-
698689
// We prevent the default action down here so that we know that dragging has started. This is
699690
// important for touch devices where doing this too early can unnecessarily block scrolling,
700691
// if there's a dragging delay.
@@ -1246,11 +1237,11 @@ export class DragRef<T = any> {
12461237
if (this._boundaryRect) {
12471238
const {x: pickupX, y: pickupY} = this._pickupPositionInElement;
12481239
const boundaryRect = this._boundaryRect;
1249-
const previewRect = this._previewRect!;
1240+
const {width: previewWidth, height: previewHeight} = this._getPreviewRect();
12501241
const minY = boundaryRect.top + pickupY;
1251-
const maxY = boundaryRect.bottom - (previewRect.height - pickupY);
1242+
const maxY = boundaryRect.bottom - (previewHeight - pickupY);
12521243
const minX = boundaryRect.left + pickupX;
1253-
const maxX = boundaryRect.right - (previewRect.width - pickupX);
1244+
const maxX = boundaryRect.right - (previewWidth - pickupX);
12541245

12551246
x = clamp(x, minX, maxX);
12561247
y = clamp(y, minY, maxY);
@@ -1518,6 +1509,17 @@ export class DragRef<T = any> {
15181509

15191510
return coerceElement(previewContainer);
15201511
}
1512+
1513+
/** Lazily resolves and returns the dimensions of the preview. */
1514+
private _getPreviewRect(): ClientRect {
1515+
// Cache the preview element rect if we haven't cached it already or if
1516+
// we cached it too early before the element dimensions were computed.
1517+
if (!this._previewRect || (!this._previewRect.width && !this._previewRect.height)) {
1518+
this._previewRect = (this._preview || this._rootElement).getBoundingClientRect();
1519+
}
1520+
1521+
return this._previewRect;
1522+
}
15211523
}
15221524

15231525
/**

0 commit comments

Comments
 (0)