Skip to content

Commit 91e4c36

Browse files
committed
fix(drag-drop): incorrectly sorting element inside dialog with blocked scrolling
We use the `ViewportRuler` to determine how much a page has been scrolled in order to compensate for it in some of the `ClientRect`-related calculations. This breaks down when the drop list is inside a dialog with blocked scrolling, because scroll blocking works by offsetting the `html` node which in turn throws off the `ViewportRuler`. These changes switches to reading the values off the `window` which won't be thrown off. Fixes #14280.
1 parent e7b0e40 commit 91e4c36

File tree

3 files changed

+25
-7
lines changed

3 files changed

+25
-7
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,22 @@ describe('CdkDrag', () => {
15071507
}));
15081508
}));
15091509

1510+
it('should sort correctly if the <html> node has been offset', fakeAsync(() => {
1511+
const documentElement = document.documentElement!;
1512+
const fixture = createComponent(DraggableInDropZone);
1513+
fixture.detectChanges();
1514+
1515+
documentElement.style.position = 'absolute';
1516+
documentElement.style.top = '-100px';
1517+
1518+
assertDownwardSorting(fixture, fixture.componentInstance.dragItems.map(item => {
1519+
return item.element.nativeElement;
1520+
}));
1521+
1522+
documentElement.style.position = '';
1523+
documentElement.style.top = '';
1524+
}));
1525+
15101526
it('should move the placeholder as an item is being sorted down on a scrolled page',
15111527
fakeAsync(() => {
15121528
const fixture = createComponent(DraggableInDropZone);

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,13 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
168168
@Inject(DOCUMENT) private _document: any,
169169
private _ngZone: NgZone,
170170
private _viewContainerRef: ViewContainerRef,
171-
viewportRuler: ViewportRuler,
171+
_viewportRuler: ViewportRuler,
172172
dragDropRegistry: DragDropRegistry<DragRef, DropListRef>,
173173
@Inject(CDK_DRAG_CONFIG) config: DragRefConfig,
174174
@Optional() private _dir: Directionality,
175175

176176
/**
177-
* @deprecated `viewportRuler` and `dragDropRegistry` parameters
177+
* @deprecated `_viewportRuler` and `dragDropRegistry` parameters
178178
* to be removed. Also `dragDrop` parameter to be made required.
179179
* @breaking-change 8.0.0.
180180
*/
@@ -185,8 +185,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
185185
if (dragDrop) {
186186
this._dragRef = dragDrop.createDrag(element, config);
187187
} else {
188-
this._dragRef = new DragRef(element, config, _document, _ngZone, viewportRuler,
189-
dragDropRegistry);
188+
this._dragRef = new DragRef(element, config, _document, _ngZone, dragDropRegistry);
190189
}
191190

192191
this._dragRef.data = this;

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
*/
88

99
import {EmbeddedViewRef, ElementRef, NgZone, ViewContainerRef, TemplateRef} from '@angular/core';
10-
import {ViewportRuler} from '@angular/cdk/scrolling';
1110
import {Direction} from '@angular/cdk/bidi';
1211
import {normalizePassiveListenerOptions} from '@angular/cdk/platform';
1312
import {coerceBooleanProperty, coerceElement} from '@angular/cdk/coercion';
@@ -269,7 +268,6 @@ export class DragRef<T = any> {
269268
private _config: DragRefConfig,
270269
private _document: Document,
271270
private _ngZone: NgZone,
272-
private _viewportRuler: ViewportRuler,
273271
private _dragDropRegistry: DragDropRegistry<DragRef, DropListRef>) {
274272

275273
this.withRootElement(element);
@@ -661,7 +659,12 @@ export class DragRef<T = any> {
661659
this._initialContainer = this._dropContainer!;
662660
this._pointerMoveSubscription = this._dragDropRegistry.pointerMove.subscribe(this._pointerMove);
663661
this._pointerUpSubscription = this._dragDropRegistry.pointerUp.subscribe(this._pointerUp);
664-
this._scrollPosition = this._viewportRuler.getViewportScrollPosition();
662+
663+
// Note that we use the scrollX and scrollY directly, instead of going through the
664+
// ViewportRuler, because the first value the ruler looks at is the top/left offset of the
665+
// `document.documentElement` which works for most cases, but breaks if the element
666+
// is offset by something like the `BlockScrollStrategy`.
667+
this._scrollPosition = {top: window.scrollY, left: window.scrollX};
665668

666669
if (this._boundaryElement) {
667670
this._boundaryRect = this._boundaryElement.getBoundingClientRect();

0 commit comments

Comments
 (0)