Skip to content

Commit 4c9224b

Browse files
committed
fix: don't fire drop events when the droppable element is scrolled out of the view
1 parent c428eed commit 4c9224b

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

src/droppable.directive.ts

+24-8
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,10 @@ export class DroppableDirective implements OnInit, OnDestroy {
8383
this.element.nativeElement,
8484
this.dragActiveClass
8585
);
86-
const droppableRectangle: {
87-
cache?: ClientRect;
86+
const droppableElement: {
87+
rect?: ClientRect;
8888
updateCache: boolean;
89+
scrollContainerRect?: ClientRect;
8990
} = {
9091
updateCache: true
9192
};
@@ -96,23 +97,38 @@ export class DroppableDirective implements OnInit, OnDestroy {
9697
: 'window',
9798
'scroll',
9899
() => {
99-
droppableRectangle.updateCache = true;
100+
droppableElement.updateCache = true;
100101
}
101102
);
102103

103104
let currentDragDropData: any;
104105
const overlaps$ = drag$.pipe(
105106
map(({ clientX, clientY, dropData }) => {
106107
currentDragDropData = dropData;
107-
if (droppableRectangle.updateCache) {
108-
droppableRectangle.cache = this.element.nativeElement.getBoundingClientRect();
109-
droppableRectangle.updateCache = false;
108+
if (droppableElement.updateCache) {
109+
droppableElement.rect = this.element.nativeElement.getBoundingClientRect();
110+
if (this.scrollContainer) {
111+
droppableElement.scrollContainerRect = this.scrollContainer.elementRef.nativeElement.getBoundingClientRect();
112+
}
113+
droppableElement.updateCache = false;
110114
}
111-
return isCoordinateWithinRectangle(
115+
const isWithinElement = isCoordinateWithinRectangle(
112116
clientX,
113117
clientY,
114-
droppableRectangle.cache as ClientRect
118+
droppableElement.rect as ClientRect
115119
);
120+
if (droppableElement.scrollContainerRect) {
121+
return (
122+
isWithinElement &&
123+
isCoordinateWithinRectangle(
124+
clientX,
125+
clientY,
126+
droppableElement.scrollContainerRect as ClientRect
127+
)
128+
);
129+
} else {
130+
return isWithinElement;
131+
}
116132
})
117133
);
118134

test/droppable.directive.spec.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -301,19 +301,34 @@ describe('droppable directive', () => {
301301
triggerDomEvent('mousedown', draggableElement, { clientX: 5, clientY: 10 });
302302
triggerDomEvent('mousemove', draggableElement, {
303303
clientX: 5,
304-
clientY: 60
304+
clientY: 11
305305
});
306-
scrollFixture.componentInstance.scrollContainer.elementRef.nativeElement.scrollTop = 100;
306+
scrollFixture.componentInstance.scrollContainer.elementRef.nativeElement.scrollTop = 150;
307307
scrollFixture.debugElement
308308
.query(By.directive(DraggableScrollContainerDirective))
309309
.triggerEventHandler('scroll', {});
310310
triggerDomEvent('mousemove', draggableElement, {
311311
clientX: 5,
312-
clientY: 61
312+
clientY: 10
313313
});
314-
triggerDomEvent('mouseup', draggableElement, { clientX: 5, clientY: 61 });
314+
triggerDomEvent('mouseup', draggableElement, { clientX: 5, clientY: 10 });
315315
expect(scrollFixture.componentInstance.drop).to.have.been.calledWith({
316316
dropData: { foo: 'bar' }
317317
});
318318
});
319+
320+
it('should not fire drop events when the element is scrolled out of the view', () => {
321+
const scrollFixture = TestBed.createComponent(ScrollTestComponent);
322+
scrollFixture.detectChanges();
323+
document.body.appendChild(scrollFixture.nativeElement);
324+
const draggableElement =
325+
scrollFixture.componentInstance.draggableElement.nativeElement;
326+
triggerDomEvent('mousedown', draggableElement, { clientX: 5, clientY: 10 });
327+
triggerDomEvent('mousemove', draggableElement, {
328+
clientX: 5,
329+
clientY: 150
330+
});
331+
triggerDomEvent('mouseup', draggableElement, { clientX: 5, clientY: 150 });
332+
expect(scrollFixture.componentInstance.drop).not.to.have.been.called;
333+
});
319334
});

0 commit comments

Comments
 (0)