blazor-dragdrop
blazor-dragdrop copied to clipboard
`DragTargetItem` is always null because `DragEnter` is immediately followed by a `DragLeave`
Hi there,
I am trying to implement a "user can drop this specific item on that specific target item only" functionality. This requires to check for specifics of the target item like it's type.
This requires issue [TBD] fixed. Even when this issue is fixed this does not seem to work reliably in all cases because DragEnter
is immediately followed by a DragLeave
when first start dragging.
You can test this for yourself by
- adding a breakpoint in
Dropzone.OnDragEnter
- enable
Actions
, setOutput window message
toWarning: DragEnter {item}
, enableContinue code execution
- enable
- adding a breakpoint in
Dropzone.OnDragLeave
- enable
Actions
, setOutput window message
toWarning: DragLeave ActiveItem = {DragDropService.ActiveItem} DragTargetItem = {DragDropService.DragTargetItem}
, enableContinue code execution
- enable
I have done this in the AllowsDrag
example and when dragging Item 1
slowly to Item 2
the output renders the following lines:
Warning: DragEnter {Item 1} <- user starts dragging item 1
Warning: DragLeave ActiveItem = {Item 1} DragTargetItem = null <- user drags item 1 outside of it's own bounds
Warning: DragEnter {Item 2} <- user enters item 2 as drop target
Warning: DragEnter {Item 2} <- now things begin to break, we get a second enter although we are already hovering over item 2 ...
Warning: DragLeave ActiveItem = {Item 1} DragTargetItem = {Item 2} <- ... but then `DragLeave` is called immediatelly afterwards removing `Item 2` as current drag target from the `DragDropService`
The last DragLeave
clears the DragTargetItem
in DragDropService
which in return means that logic implemented in OnDrop
does not have access to the drag target anymore. So if you need the drag target in your logic to persist the drag operation then you cannot do this right now because there is no drag target at this point.
Now, in the beginning of this issue I wrote "does not seem to work reliably" and "when first start dragging". This is because after a while, when entering / leaving a specific area multiple times, the event order changes to DragLeave
then DragEnter
and everything works as expected. So lets just continue dragging Item 1
outside of Item 2
then again onto Item 2
and repeat until the Output window suddenly changes its output to:
...
Warning: DragLeave ActiveItem = {Item 1} DragTargetItem = {Item 2} <- user leaves item 2
Warning: DragEnter {Item 2} <- user enters item 1
Warning: DragLeave ActiveItem = {Item 1} DragTargetItem = {Item 2}
Warning: DragEnter {Item 2}
Warning: DragLeave ActiveItem = {Item 1} DragTargetItem = {Item 2}
Warning: DragEnter {Item 2}
Does anyone have an idea what could cause the wrong event call order in the beginning? Can we fix this somehow?
So lonG
Daniel
I found the following sections while reading the gist from @MackinnonBuck which most likely describes what the issue with the event order is, quote:
I think there could be scenarios where event callbacks occur in the wrong order, resulting in undesirable behavior. For example, if onDragStart blocks for five seconds somehow, and onDragEnd fires before onDragStart completes, things could be executed in the wrong order.
https://gist.github.com/MackinnonBuck/374e529e9c3fdb9d228214b4cc79e617
@ViRuSTriNiTy I am pretty sure you did but just want to make sure , you disabled pointer events?
.plk-dd-inprogess > * { pointer-events: none; }
@Postlagerkarte Yes, I have this section in my css file.
Ok, somehow the issue seems to be the outer draggable item.
Lets say I have the following structure of draggable items each in a separate dropzone
Page
Section Y
Question Y2
then when dragging Question Y2 the debug output looks like this (error and warning is just for coloring):
As we can see, OnDragEnter is first called for Section Y, then for Question Y2 but then OnDragLeave for Section Y is directly called afterwards.
Btw: using
.plk-dd-inprogess > * {
pointer-events: none;
}
in the hope to fix this issue makes it even worse as often plk-dd-inprogess
is left in the draggables and then no pointer events are received anymore and drag & drop is completely broken.
Also I more and more think that the wrong event order is a Blazor bug as setting @on[mouse@|drag]***:stopPropagation
on the root div and the draggables doesn't make a difference whatsoever. Either Blazor ignores it, does not implement it correctly or the browsers do their own thing. The events are always bubbling up.
Perhaps we could change OnDragLeave
from
public void OnDragLeave()
{
DragDropService.DragTargetItem = default;
DragDropService.ShouldRender = true;
StateHasChanged();
DragDropService.ShouldRender = false;
}
to
public void OnDragLeave(TItem item)
{
// condition ensures that we only reset the target item that has been previously set
if (item == DragDropService.DragTargetItem)
{
DragDropService.DragTargetItem = default;
DragDropService.ShouldRender = true;
StateHasChanged();
DragDropService.ShouldRender = false;
}
}