-
Notifications
You must be signed in to change notification settings - Fork 6.8k
drag-drop: make the view scroll when trying to move a draggable outside the current view #13588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
There's been a TODO for it, but I've mostly held back until now since it's tricky figuring out which element should be scrolled. |
Is there any intermediate way to make it work with dom-autoscroller until TODO is addressed? |
@crisbeto I've implemented auto scrolling on CdkDropList in my private fork. It doesn't cover scenarios where the drop list is wider/taller than its scroll parent but it works fine when the drop list fits on the screen. If you think it'd be useful, I can set aside some time to prepare a PR. |
@JohnKis the scrolling logic here isn't really the issue. We've held back on implementing it until now, because it's tricky knowing which element we're supposed to scroll. |
@crisbeto Understood, just figured I’d ask. Thanks |
@crisbeto I think we could use cdk-scrollable as marker for element to scroll |
Hi guys. Any ideas on when to expect the fix? |
Hey, any update on this thread? |
Hi. I have a business case where multiple (say more than 10) containers are stacked vertical. So, need to think about this case as well while implementing auto-scrolling. Maybe for this solution it's possible to incorporate event cdkDropListEntered. |
The cdkDropListEntered event already exists (cdkDragEntered), but doesn't solve the problem. eg. the case where your dropzones are in a scrollable container and the height of a drop zone is greater than the one of the container, so as only one dropZone is displayed. The supposed cdkDropListEntered event will never be emitted. Would it be possible to make a CdkdropListGroup aware of it's container, so that it can be conscious of how it should behave when moving an item towards the displayed edges of that container? |
I have been trying to come up with a work-around that does not rely on specific functionality by the component library. My approach was to add transparent divs at the top and the bottom of the scrollable container und to watch for mouseenter/mouseleave events to scroll the container. Unfortunately, this did not work as the framework stops the propagation of these events. I don't know if this behavior could be chanhged more easily than coming up with brand new concepts to deal with the matter. |
Any updates so far? |
Can you just watch for window.height and window.width and check, if the container extends further, then if it is drag action, then if mouse is down (meaning something is being dragged), then scroll the page accordingly? |
@aidvb I have a solution but it comes with its own problems |
@aidvb Maybe this would work with scrolling the entire page, in my use case, however, I would like to scroll individual divs. Also, I am not sure if I need browser events to capture the mouse actions and since material cancels the event popagation, I would end up where I started. |
@agent0 How's it going to solve the problem? |
+1 for this |
@aidvb It would not solve the problem as such but it would enable me to implement my own scrolling trigger to scroll the underlying div manually. As it stands now, I cannot detect that the drag is hovering a border area of the div. |
+1 for this |
Any progress on solving this issue? |
Definitely going to +1 this. We're getting ready to implement a work-around using the cdkDragMoved event but that feels like a really poor decision for long run. |
Would love to have a solution for this. Need to scroll something out of the viewport. |
Is there any workaround for this? I really need this because I have not that much space and I want to allow users to drag and drop inside a small container that is scrollable. |
@TheKeymaster The CDK drag&Drop currently calculates drop position in such a way that moving the scroll position of the container while dragging interferes with this calculation. Any work-around to detect the hover position of the drug object is limited by that. If you are There is an open issue to address that concern #14098 as well. |
+1 Any temporary fix for this? |
@Achilles1515 it depends on which is your scrollable element. At the moment it's set up to only scroll the window or the list itself. It starts scrolling when you're dragging and the pointer is close to the edge of the element. |
@crisbeto I got it working as you say: scroll just the list itself. |
@crisbeto |
Unfortunately it does not work within a Material Table at all. :( I can scroll with mouse wheel now, but the distance between the drag placeholder and the dragged element is increasing while scrolling. |
Should be able to add directive to the container which we want to be able to scroll y and scroll x |
Trying to build a Kanban board and dragging a card won't scroll the parent container horizontally. |
but this works only with drop list if i have a box inside a container div when i drag the box it's container is not scrolling ! :/ |
@crisbeto |
That might be because the scroll regions are overlapping. I've got #16675 to help with it. |
+1 for @nkartchner 's stakblitz example. Even if you manually scroll the board when the ticket is being dragged the drop containers do not 'register' so when they scroll into view you still can't drop the ticket on them |
@crisbeto hi! are there plans to make this possible for mobile as well? |
It should work on mobile already. |
Works for me but only for nearest scrollable parent it seems. Also, is there a way to set the scroll speed?
|
need a way to set scroll speed, especially when the list is too long |
|
Inject Document and set id to container for all drag list items to move the horizontal scrollbar when emitting dragMove event
|
@Mustafa-Omran can you explain bit more ? |
I had made this code, but I just found that it works if updating haha I will stay here if anyone wants to do this in older versions. This is an object that you place in the document where dragMoved is in function, and call part of it inside dragMoved to work: //AUTOSCROLL IMPLEMENTATION
autoScrollSetup = {
isOnEdge:false,
itsStarted:false,
scroll(side:any,elContainer:any,everyXms:any,stepPx:any,direction:any):any{
if(this.isOnEdge){ // Mouse in the edge enough to scroll?
if(!this.itsStarted){ // Event already started?
this.itsStarted = true;
// Check the direction
let elScroll:any;elScroll;
if(direction==="horizontal"){
elScroll = "scrollLeft";
}
else
if(direction==="vertical"){
elScroll = "scrollTop";
}
// Runs from time to time
setTimeout(() => {
if(side==="leftOrTop") {elContainer![elScroll] -= stepPx} // It's on the left side (if it's horizontal) or top (if it's vertical) ?
else
if(side==="rightOrBottom") {elContainer![elScroll] += stepPx} // It's on the right side (if it's horizontal) or bottom (if it's vertical) ?
this.itsStarted = false; // Finish
this.scroll(side,elContainer,everyXms,stepPx,direction); // Rerun
}, everyXms);
}
}
},
autoScroll(objConfig:any){
// Set default values
var {event,lateralTolerancePx=40,stepPx=5,everyXms=30,direction='horizontal'} = objConfig;
// Get element Container and this position
var elContainer = event.source.dropContainer.element.nativeElement;
var elContainerBCR = elContainer!.getBoundingClientRect();
// Check direction
let elContainer1:any;
let elContainer2:any;
let xy:any;
if(direction==="horizontal"){
elContainer1 = elContainerBCR.left;
elContainer2 = elContainerBCR.right;
xy = 'x';
}
else
if(direction==="vertical"){
elContainer1 = elContainerBCR.top;
elContainer2 = elContainerBCR.bottom;
xy = 'y';
}
if(event.pointerPosition[xy] <= elContainer1+lateralTolerancePx){ // Is mouse position left/top enough to start scrolling?
this.isOnEdge = true;
this.scroll("leftOrTop",elContainer,everyXms,stepPx,direction);
}
else if(event.pointerPosition[xy] >= elContainer2-lateralTolerancePx){ // Is mouse position right/bottom enough to start scrolling?
this.isOnEdge = true;
this.scroll("rightOrBottom",elContainer,everyXms,stepPx,direction);
}
else{
this.isOnEdge = false;
}
}
} Inside dragMoved: dragMoved(event: CdkDragMove<string[]>){
//Auto Scroll: event*(required), direction(horizontal or vertical), lateralTolerancePx, stepPx, everyXms
this.autoScrollSetup.autoScroll({'event':event,'direction':'horizontal'})
} besides calling dragMoved inside each list element. |
HTML ` Itmes<div class="overflow-container" cdkDropList (cdkDropListDropped)="onDropItem($event)" [cdkDropListData]="items"> <ul *ngFor="let item of items" class="item" [cdkDragData]="item" cdkDrag (cdkDragMoved)="onDragMoved($event)"> <app-item [item]="item">
|
…d viewport Currently for performance reasons we only support scrolling within the drop list itself or the viewport, however in some cases the scrollable container might be different. These changes add a new input that consumers can use to tell the CDK which other parents can be scrolled. Fixes angular#18072. Relates to angular#13588.
#18082 will allow for elements that aren't the list or the viewport to be scrolled. |
…d viewport Currently for performance reasons we only support scrolling within the drop list itself or the viewport, however in some cases the scrollable container might be different. These changes add a new input that consumers can use to tell the CDK which other parents can be scrolled. Fixes angular#18072. Relates to angular#13588.
…d viewport Currently for performance reasons we only support scrolling within the drop list itself or the viewport, however in some cases the scrollable container might be different. These changes add a new input that consumers can use to tell the CDK which other parents can be scrolled. Fixes angular#18072. Relates to angular#13588.
…d viewport (#18082) Currently for performance reasons we only support scrolling within the drop list itself or the viewport, however in some cases the scrollable container might be different. These changes add a new input that consumers can use to tell the CDK which other parents can be scrolled. Fixes #18072. Relates to #13588.
…d viewport (angular#18082) Currently for performance reasons we only support scrolling within the drop list itself or the viewport, however in some cases the scrollable container might be different. These changes add a new input that consumers can use to tell the CDK which other parents can be scrolled. Fixes angular#18072. Relates to angular#13588.
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Bug, feature request, or proposal:
When trying to drag a cdkDragItem outside of the view, it does not scroll to show the rest of the cdkDrop div / the rest of the page.
What is the expected behavior?
The view should scroll towards the direction in which the element is being dragged to reveal the rest of the page.
What is the current behavior?
The view doesn't scroll, the droppable item cannot move out of the current view
What are the steps to reproduce?
In the following stackblitz, try to drag an item from the start of the list to the bottom of the list.
https://stackblitz.com/edit/angular-emaoau
What is the use-case or motivation for changing an existing behavior?
The current behaviour feels very restrictive. you could have to take multiple steps if you want to drag and drop an element in a larger list.
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
The text was updated successfully, but these errors were encountered: