i came across a bug for Chrome and Opera and i would like to know if its known and if so, is there a solution?
If i change the DOM on the dragstart event it immediately fires the dragend event?! Is this a bug or is there some reason behind it? Only happens in Chrome and Opera. Firefox works.
I appreciate every answer.
$('body').on({
dragstart: function(e) {
dragProfilefieldSrcElformid = $(this).attr("data-profilefieldid-formid");
e.dataTransfer = e.originalEvent.dataTransfer;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', $(this).attr("data-profilefieldid"));
// Changing the DOM, fires the dragend Event in Chrome?
$("#plugin_loginlogout_pfcontainer_" + dragProfilefieldSrcElformid).find(".plugin_loginlogout_pf_entryfield").addClass("highlight"); // This doesn't work in Chrome and Opera, but in Firefox
},
dragend: function() {
console.log("dragend");
}
".plugin_loginlogout_pf");
Edit:
Putting the DOM Change in a setTimeout Function seems to solve the problem!
It seems that different browsers manifest different behaviors towards long running operations.
JavaScript has a single thread that runs all of your instructions in the same queue. Each queue item is run in sequence and once the item has finished execution, the next item (from the queue) is grabbed and run.
The culprit for long running operation is the change you try to bring to the DOM (which I assume is preceded by a heavy search using find()
that will run the DOM manipulation for each matched element).
What happens as you drag the element is that, all lines of code in the
dragstart
handler, and as you stop dragging, thedragend
handler are pushed to the message queue respectively in order to be executed serially. However the DOM manipulation is taking more time (probably a few milliseconds more) to execute than the execution of thedragend
handler before you stop dragging, and therefore, it appears as if thedragend
fired way too soon.
Note: Sometimes block(s) of code create a new event and hence are pushed to the end of the browser event queue (or maybe somewhere after the item that's being run), resulting in a later execution. (I suppose the nature of it differs from browser to browser.)
The DOM manipulation part of your code might face such an issue in Chrome and Opera, though I'm not sure.
setTimeout(fn, 0)
TrickThe workaround for such situations is to wrap the long running operation block in a setTimeout
function with 0
time.
(You can think of this as telling the browser to run the part of your code, in no time at all!, not literally though.)
Once a block of code has done execution, the browser will search for the available items waiting to be run, and the ones with setTimeout
or setInterval
will be pushed to the queue upon first available moment.
In your particular case, the trick is that setTimeout
defers the execution of DOM change to a later time (at least 0
seconds) than the dragend
event handler, thereby giving the impression as if the dragend
event fired after the DOM change.
There is a great post by @DVK here explaining why setTimeout(fn, 0)
is sometimes useful. Do check the JSfiddle by him (in Chrome) as well.
As pointed by @MojoJojo and @Pradeep, it seems that Webkit browsers (older versions of Chrome in particular) have an issue with drag
events. However, I tried to reproduce the bug in Chrome Version 47.0.2526.106 (newest version as of 11th January 2016), and the drag
events fired without any irregularities.
Anyway, even if there was a bug, the setTimeout
trick still applies as a proper workaround for the issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With