Steps to reproduce:
Drag / Drop to all lists contained in cdkDropListConnectedTo
Items from inner Lists may only be dropped to outer lists, not to sibling or their own lists
When using CDK drag / drop (8.0.0 up to and including 8.1.2) with nested
lists, two issues arise that prevent an easy use of the feature:
a) dragging does not work from inner list to inner list
When dragging an inner item (e.g. Brush teeth) it is only possible to
drop it in the outer list, not in its own list and not in its sibling list.
It turns out, that order in cdkDropListConnectedTo is important: when
I reverse the items, it will partially work: See
https://stackblitz.com/edit/angular-drag-and-drop-child-groups-mxrkae?file=app%2Fcdk-drag-drop-connected-sorting-group-example.html
Still, it is not possible to drop an item from an inner list in into
its own list
b) dragging does not work in the drop item's source list
See above
You may find a hack for this in
https://stackblitz.com/edit/angular-drag-and-drop-child-groups-35em6n?file=app/cdk-drag-drop-connected-sorting-group-example.html
Explanation and proposed solution.
For above case a) mentioning it in the documentation may be sufficient -
it can be influenced from the outside. However, a more intelligent
solution (e.g. identifying the toplevel sublist) would be nice.
For case b), filtering out the source list in
src/cdk/drag-drop/directives/drop-list.ts seems to cause the issue:
ref.connectedTo(siblings.filter(drop => drop && drop !==
this).map(list => list._dropListRef))
My hack replaces this by an unfiltered list - in quite an ugly manner.
it doesnt work well, cant get needed element index in nested array.
+1
Setting as a P2 based on the number of duplicate issue we get about this.
From @matthewerwin in #19085:
Reproduction
Use StackBlitz to reproduce your issue:
https://stackblitz.com/edit/angular-rf6gg6
Steps to reproduce:
- Look at the stack blitz.
- Markup has an effect on ability to even start a drag without any console or compile indicator that cdkDrag and cdkDropList cannot be on the same drag element (they could be in v8 --v9 allows them on the same container for the "drop element")
- Exit/Enter aren't reliably detected based on the client-rect
Expected Behavior
What behavior were you expecting to see?
- Drop zone container should always be detected as soon as the mouse goes over the element.
- If use of cdkDrag/cdkDropList combo only works in certain situations (e.g. codebase looks for this._container on a dragref in v9...which appears to only get set if cdkDropList is on a parent element). That should either be documented and also the compiler should write an error to the console...or the code should be adjusted to set this._container to the element itself to handle the directive combo on the same element.
Actual Behavior
What behavior did you actually see?
- No errors to console or at compile time with directives appended in any fashion.
- v9 does not detect a drop-zone accurately at all for entry or exit. Shaking the mouse a bunch over drop zones or redragging repeatedly will randomly then detect it correctly...though continuing to drag around shows the same inability to detect the drop-zones.
+1
So it seems like there is some internal priority here. I've gotten pretty decent results with sorting the lists by dom depth as a workaround:
this.connectedDroplists$ = this._connectedDroplists$.pipe(
debounceTime(16),
tap((connectedDropLists) => {
// sort the lists by depth to prefer deeper lists
connectedDropLists.sort((a, b) => {
return (
this._getDepth(b.element.nativeElement) -
this._getDepth(a.element.nativeElement)
);
});
}),
shareReplay(1)
) as BehaviorSubject<CdkDropList[]>;
It seems that no matter what I do, I can't seem to get it to re-order within the source droplist where I grabbed an item from.
Sorting the droplists by element depth and using the enforce hack that @shesse has provided, I have gotten an excellent result even with completely overlapping nested drop lists (looks like I had a gap that allowed for me to add to the parent). Thank you @shesse!
I suppose the reversing makes sense because the deeper the list is the later it would be registered (resulting it to be at the end).

Hi everyone,
I ran into this issue a few days ago and decided to make an attempt at fixing it :-) I have tried to summarise my "analysis" of the issue and a proposal for how to solve it below. I apologise for - to some extent - repeating what has already been said above. I have also attached "Monkey Patch" that seems to fix the issue for Angular Material v11.0.3. I will try to transform it into a pull request shortly.
The main issue seems to be with the implementation of _getSiblingContainerFromPosition in DropListRef which is used by _updateActiveDropContainer in DragRef to identify whether a draggable item is being moved over a new (and connected) drop container and, if it is, which drop container the item is being moved over.
Based on the code and comments in _updateActiveDropContainer (which is the only place where _getSiblingContainerFromPosition is called), _getSiblingContainerFromPosition is expected to return the DropListRef for the drop container that the item is being moved over, provided that it is not the drop container that it currently belongs to. The method is expected to return 'undefined' if the item is being moved over the current drop container or if it is being moved over something that is not a drop container.
The current implementation of _getSiblingContainerFromPosition does this by returning the first connected drop container ("sibling") in the list of siblings that has a client rect that contains the current position of the item being dragged and for which enterPredicate returns true (I know this is somewhat simplified, but the still argument holds). This approach works perfectly well as long the client rects of the drop containers are not overlapping.
However, when drop containers are nested (and therefore overlapping), this causes two problems:
The first issue can be addressed by ordering the items of 'cdkDropListConnectedTo' (as mentioned above). The current drop container can, however, not be added to siblings due to the code in _setupInputSyncSubscription of DropList that actively removes 'this' from the list (as pointed out by @shesse). The hack described by @shesse above addresses this issue by forcing the 'this' entry back into the siblings list. This approach does, however, bring the risk of breaking other code as the siblings list is clearly not intended to include 'this'.
My proposal would be to fix the issue by rewriting _getSiblingContainerFromPosition such that it correctly handles nested drop containers without any assumptions on the order of the siblings list. This could be done in the following way:
I have created a "Monkey Patch" that seems to work with Angular Material version 11.0.3 (attached). It should be straight forward to transform this into a pull request. I will gladly do so (but never having done a pull request before, I'll have to read up on how to do it)
I suspect thet the code breaks more than one Angular Material coding guideline. It is also a quick write-up so I would not be surprised if there are some issues that need to be resolved. A proper code review might be in order ... :-)
3 years ago I tried to use drag-drop, but got stuck, some issues were closed due to inactivity. I might have a need in drag-drop in half a year, maybe I will immediately look for another implementation. So I am far off, what is currently implemented or which issues are open and solved, and if this is the correct place for:
@FritzHerbers
I propose you start by browsing through the excellent documentation for CDK Drag and Drop. I think you will find that the drag-drop feature has improved significantly over the last couple of years. You will likely also find the answer to your callback question there. Have a look at cdkDropListEnterPredicate and cdkDropListSortPredicate.
The issue tracker and this particular issue is, however, not the right place for a general discussion about the state of cdk/drag-drop nor your specific question of support for a programatic callback. If you have further questions, community support requests can be submitted at StackOverflow or in the Angular Material gitter channel.
Please refer to the official instruction for support questions for more details.
hi @soren-petersen. can you attach stackblitz link for the same.
It will be very helpful. thanks
Hi @Akhil-Myadarapu,
I'm sorry, but I really do not have the time to put together a presentable demo right now. Feel free to put one up if you have more time on your hands than I.
In order to use the "monkey patch" that I attached in a previous post, you only need to import the "installPatch" function from the module:
import { installPatch } from './nested-drag-drop-patch'
and then call it at the root level of your .ts file:
installPatch();
Apart from that, you need to set up a nested tree with cdkDropList and cdkDrop in your template. Remember to use cdkDropListConnectedTo to connect all the drop lists. Using cdkDropListGroup will not work for a nested setup.
You might find that the patch generates some warnings when running lint. These have been fixed in the pull request. Have a look at that if you want the latest version of the fix.
@Akhil-Myadarapu,
I added the monkey patch to @shesse's original StackBlitz, and then replaced its content with the method bodies from the PR (commit d3690c3):
It works pretty good!
@soren-petersen During dragging, there's some trouble transitioning to a nested list (coming from the top, it doesn't change until the 2nd or 3rd item down; coming from the bottom it wants to drop _before_ the nested list for some pixels, than switches to _into_.) Not sure if I should make the comments in the PR itself as well?
@soren-petersen I've used the zip.file to patch the cdk and it does solve the original issue here.
https://stackblitz.com/edit/angular-10-clarity-4-dragdrop-nested-with-fix
However dragging an item from a child to it's parent seems to have very narrow window. In my example the preview element has a height of 20px. Without the patch, the window works as expected (with the bug of this issue of course).
With the patch the window seems to be only like a pixel or so.
So it seems like there is some internal priority here. I've gotten pretty decent results with sorting the lists by dom depth as a workaround:
this.connectedDroplists$ = this._connectedDroplists$.pipe( debounceTime(16), tap((connectedDropLists) => { // sort the lists by depth to prefer deeper lists connectedDropLists.sort((a, b) => { return ( this._getDepth(b.element.nativeElement) - this._getDepth(a.element.nativeElement) ); }); }), shareReplay(1) ) as BehaviorSubject<CdkDropList[]>;~It seems that no matter what I do, I can't seem to get it to re-order within the source droplist where I grabbed an item from.~
Sorting the droplists by element depth and using the enforce hack that @shesse has provided, ~I have gotten an excellent result even with completely overlapping nested drop lists~ (looks like I had a gap that allowed for me to add to the parent). Thank you @shesse!
I suppose the reversing makes sense because the deeper the list is the later it would be registered (resulting it to be at the end).
Hello admosiry,
Is there any demo for the image provided? I am looking to do something similar. I am using flex to define double/single columns and I am having issues while dragging. Elements flipping while dragging
thanks @soren-petersen ! Your patch just saved my day !
Most helpful comment
Hi everyone,
I ran into this issue a few days ago and decided to make an attempt at fixing it :-) I have tried to summarise my "analysis" of the issue and a proposal for how to solve it below. I apologise for - to some extent - repeating what has already been said above. I have also attached "Monkey Patch" that seems to fix the issue for Angular Material v11.0.3. I will try to transform it into a pull request shortly.
The main issue seems to be with the implementation of _getSiblingContainerFromPosition in DropListRef which is used by _updateActiveDropContainer in DragRef to identify whether a draggable item is being moved over a new (and connected) drop container and, if it is, which drop container the item is being moved over.
Based on the code and comments in _updateActiveDropContainer (which is the only place where _getSiblingContainerFromPosition is called), _getSiblingContainerFromPosition is expected to return the DropListRef for the drop container that the item is being moved over, provided that it is not the drop container that it currently belongs to. The method is expected to return 'undefined' if the item is being moved over the current drop container or if it is being moved over something that is not a drop container.
The current implementation of _getSiblingContainerFromPosition does this by returning the first connected drop container ("sibling") in the list of siblings that has a client rect that contains the current position of the item being dragged and for which enterPredicate returns true (I know this is somewhat simplified, but the still argument holds). This approach works perfectly well as long the client rects of the drop containers are not overlapping.
However, when drop containers are nested (and therefore overlapping), this causes two problems:
The first issue can be addressed by ordering the items of 'cdkDropListConnectedTo' (as mentioned above). The current drop container can, however, not be added to siblings due to the code in _setupInputSyncSubscription of DropList that actively removes 'this' from the list (as pointed out by @shesse). The hack described by @shesse above addresses this issue by forcing the 'this' entry back into the siblings list. This approach does, however, bring the risk of breaking other code as the siblings list is clearly not intended to include 'this'.
My proposal would be to fix the issue by rewriting _getSiblingContainerFromPosition such that it correctly handles nested drop containers without any assumptions on the order of the siblings list. This could be done in the following way:
I have created a "Monkey Patch" that seems to work with Angular Material version 11.0.3 (attached). It should be straight forward to transform this into a pull request. I will gladly do so (but never having done a pull request before, I'll have to read up on how to do it)
nested-drag-drop-patch.ts.zip
I suspect thet the code breaks more than one Angular Material coding guideline. It is also a quick write-up so I would not be surprised if there are some issues that need to be resolved. A proper code review might be in order ... :-)