-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
fix(cdk/drag-drop): support for nested drop containers (#16671) #21526
fix(cdk/drag-drop): support for nested drop containers (#16671) #21526
Conversation
Fixes a two issues with nested drop containers. The first fixed issue is that the elements of cdkDropListConnectedTo previously had to be ordered correctly to support moving items into an inner drop container. Sepcifically, inner drop containers had to be listed before their outer ancestors. The second fixed issue is that items of an inner container could not be re-ordered without moving the item out of the container and then back in. Fixes angular#16671
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
@googlebot I signed it! |
d6db608
to
d3690c3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On top of the other comments, we definitely need some unit tests to ensure that things work as expected. It would be nice to have an example in the dev app as well so nested dragging can be tested manually.
// Only consider targets where the drag postition is within the client rect | ||
// (this avoids calling enterPredicate on each possible target) | ||
let matchingTargets = targets.filter(ref => { | ||
return ref._clientRect && isInsideClientRect(ref._clientRect, x, y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that we can depend purely on the ClientRect
, because it doesn't account for overlapping containers or ones that have been scrolled out of view. That's why we have the elementFromPoint
call inside _canReceive
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code does actually not depend solely on ClientRect
. There is a call to _canRecieve
on line 849 that should handle situations were the drop container is scrolled out of view or when there are elements overlapping the target drop container.
There is, however, an implicit assumption that the ClientRect
of an inner drop container will only overlap with siblings that are its own ancestors in the drop container hierarchy. Although this is likely to be the most common case, it may not always be true. Let me see if I can find an elegant way to do away with this assumption.
* outer drop container appear before the inner drop container. | ||
* @param refs List of DropListRefs. | ||
*/ | ||
private _orderByHierarchy(refs: DropListRef[]): DropListRef[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole method is a bit concerning in terms of performance, because we call it for every pixel that the user has dragged. The DOM actually has an API that returns the relative position between two nodes: https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition. That being said, I don't know what the performance implications of the native API are either.
Alternatively, we could cache the tree structure after the first check, because the DOM is unlikely to change while the user is dragging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I share your concerns, although I might not become a problem in practice. The number of references ordred in each call to _orderByHierarchy
is limited by the depth of the drop container hierarchy. Hence, if the hierarchy is 10 levels deep (a rather massive tree), the method will be called with a list of at most 10 drop containers to sort. This is not a huge effort for a modern computer / device.
Anyway, I think caching would be a good idea.
It might also make sense to re-implement the function using "compareDocumentPosition" rather than traversing the hierarchy manually.
I'll have a go at it.
First of all, thank you for constructive feedback!
With respect to unit tests and an example in the dev app, I'm sure I would be able to put something together. Unfortunately, I would need to spend quite a bit of time to figure out how it all works. At the moment, I have no idea where the dev-app is located, let alone how to add an example. Nor am I familiar with the unit test framework. Is there, perhaps, someone with more experience as a contributor who could support me with this? |
I wrote most of the |
Really excited to see this go in guys as it relates directly to a big requirement in my current project. Thank you for your work @soren-petersen and @crisbeto. Any ideas on what version of Material it might be expected in? It would be brilliant to start using it. |
@crisbeto So still nothing has been done to fix the issue "The second fixed issue is that items of an inner container could not be re-ordered without moving the item out of the container and then back in.". There is no workaround for this. |
Is there any hope that this will ever be the solution? Or that there will be any kind of solution for this kind of feature? Should I try another approach? Any ideas? |
@crisbeto Can we please get this issue fixed, its been 3 years since people have been encountering this issue. Would really appreciate if you could spare a little bit of your time to resolve this. |
We have this issue too, can you resolve this issue ? |
Closing this particular PR since it has gotten out of sync with the repo and still needs tests added. We encourage anyone to reopen this PR with tests so we can get this merged in |
Fixes a two issues with nested drop containers. The first fixed issue is that the elements of
cdkDropListConnectedTo previously had to be ordered correctly to support moving items into an
inner drop container. Sepcifically, inner drop containers had to be listed before their outer
ancestors. The second fixed issue is that items of an inner container could not be re-ordered
without moving the item out of the container and then back in.
Fixes #16671