I have a button that is draggable inside a live view:
<button
id={"#{@id}.drag_handle"}
phx-hook="algorithm:move_vertex"
draggable="true"
data-drag-label={@vertex.label}
data-drag-vertex={@vertex.id_64}
class="flex items-center hover:text-gray-500"
>
<.icon name="icon-drag" class="w-5 h-5" />
</button>
Now “sometimes” when I drag and drop the button, it is not updated. Especially data-drag-vertex={@vertex.id_64}
.
In the console, with live view debug enabled, I see the diff for the button data attribute. And if I put another HTML element next to the button, that element is always updated.
If I update anything else in the page (not related to the button), I see the diff in the console about that part, but the button will also update correctly to catch up with the previous diff.
I did a test with the following code, putting the button twice. And only the dragged button is not updated. I always have to drag it about 5 times because it trigger the bug.
<button
id={"#{@id}.drag_handle"}
phx-hook="algorithm:move_vertex"
draggable="true"
data-drag-label={@vertex.label}
data-drag-vertex={@vertex.id_64}
>{@vertex.id_64}
</button>
<button
id={"#{@id}.drag_handle_"}
phx-hook="algorithm:move_vertex"
draggable="true"
data-drag-label={@vertex.label}
data-drag-vertex={@vertex.id_64}
>{@vertex.id_64}
</button>
I use firefox, so maybe it’s a firefox issue.
I realize this is not much to go on, but I was wondering if you had an idea how to debug this or if it was ringing a bell.
UPDATE:
I have noticed something, my hook add a dragend
listener with:
(drag_end
event doesn’t update any assign in my test)
this.el.addEventListener("dragend", (evt) => {
this.pushEvent("drag_end")
})
and if I change the code to:
this.el.addEventListener("dragend", (evt) => {
setTimeout(() => this.pushEvent("drag_end"), 100)
})
the bug is not triggered. But if I put a low value, like 10
ms in the timeout, the bug appears.
It seems there is some kind of subtle race condition somewhere.
UPDATE 2:
I realized that on drop/dragend it would fire another event that is hover state.
Basically, the two events arrive together, the dragend is at the live view level, but the hover event is at the component level:
[debug] HANDLE EVENT "drag_end" in BookWeb.CMS.IndexLive
Parameters: %{}
[debug] Replied in 25µs
[debug] HANDLE EVENT "hit_gridpoint" in BookWeb.CMS.IndexLive
Component: BookWeb.CMS.Algorithm.CanvasComponent
Parameters: %{"cx" => 1115, "cy" => 524.7999877929688, "x" => 5, "y" => 4}
[debug] Replied in 25µs
If I remove either one, the bug is gone.
UPDATE 3:
With live view profiling enabled I noticed that:
When the bug occurs:
01:27:34.922 morphdom: 5.98ms - timer ended
01:27:34.922 component patch complete: 7.76ms - timer ended
01:27:34.924 toString diff (update): 0.32ms - timer ended
01:27:34.928 morphdom: 4ms - timer ended
01:27:34.928 full patch complete: 4.48ms - timer ended
01:27:34.933 morphdom: 4.68ms - timer ended
01:27:34.934 morphdom: 0.08ms - timer ended
When it does not:
01:29:30.670 morphdom: 6.66ms - timer ended
01:29:30.670 component patch complete: 8.42ms - timer ended
01:29:30.676 morphdom: 4.92ms - timer ended
01:29:30.677 morphdom: 0.14ms - timer ended
01:29:30.684 morphdom: 5.2ms - timer ended
01:29:30.685 component patch complete: 7.46ms - timer ended
01:29:30.686 toString diff (update): 0.34ms - timer ended
01:29:30.691 morphdom: 4.54ms - timer ended
01:29:30.692 full patch complete: 6.06ms - timer ended