Skip to content

Commit

Permalink
fix(cdk/drag-drop): error if preview dimensions are accessed too early (
Browse files Browse the repository at this point in the history
#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.
  • Loading branch information
crisbeto authored Mar 1, 2022
1 parent a8ec63c commit 37be099
Showing 1 changed file with 15 additions and 13 deletions.
28 changes: 15 additions & 13 deletions src/cdk/drag-drop/drag-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export class DragRef<T = any> {
/** Whether the native dragging interactions have been enabled on the root element. */
private _nativeInteractionsEnabled = true;

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

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

// We only need the preview dimensions if we have a boundary element.
if (this._boundaryElement) {
// Cache the preview element rect if we haven't cached it already or if
// we cached it too early before the element dimensions were computed.
if (!this._previewRect || (!this._previewRect.width && !this._previewRect.height)) {
this._previewRect = (this._preview || this._rootElement).getBoundingClientRect();
}
}

// We prevent the default action down here so that we know that dragging has started. This is
// important for touch devices where doing this too early can unnecessarily block scrolling,
// if there's a dragging delay.
Expand Down Expand Up @@ -1246,11 +1237,11 @@ export class DragRef<T = any> {
if (this._boundaryRect) {
const {x: pickupX, y: pickupY} = this._pickupPositionInElement;
const boundaryRect = this._boundaryRect;
const previewRect = this._previewRect!;
const {width: previewWidth, height: previewHeight} = this._getPreviewRect();
const minY = boundaryRect.top + pickupY;
const maxY = boundaryRect.bottom - (previewRect.height - pickupY);
const maxY = boundaryRect.bottom - (previewHeight - pickupY);
const minX = boundaryRect.left + pickupX;
const maxX = boundaryRect.right - (previewRect.width - pickupX);
const maxX = boundaryRect.right - (previewWidth - pickupX);

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

return coerceElement(previewContainer);
}

/** Lazily resolves and returns the dimensions of the preview. */
private _getPreviewRect(): ClientRect {
// Cache the preview element rect if we haven't cached it already or if
// we cached it too early before the element dimensions were computed.
if (!this._previewRect || (!this._previewRect.width && !this._previewRect.height)) {
this._previewRect = (this._preview || this._rootElement).getBoundingClientRect();
}

return this._previewRect;
}
}

/**
Expand Down

0 comments on commit 37be099

Please sign in to comment.