I have a draggable element. After dragging, I want to add the click-funtion again. The click-event should not fire when dragging, but I want to add it when dragging is over.
If I add my click-event again after dragging (line 46) it get's fired immediately
clickElemtent(document.getElementById("mydiv"));
I don't understand the logic.. Thank you so much!
dragElement(document.getElementById("mydiv"));
clickElemtent(document.getElementById("mydiv"));
function clickElemtent(elmnt) {
elmnt.onclick = function() {
alert("click")
}
}
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
elmnt.onclick = null;
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement(e) {
document.onmouseup = null;
document.onmousemove = null;
e.stopImmediatePropagation();
e.stopPropagation();
clickElemtent(document.getElementById("mydiv")); ///// ?????
}
}
#mydiv {
position: absolute;
z-index: 9;
background-color: #f1f1f1;
text-align: center;
border: 1px solid #d3d3d3;
}
#mydivheader {
padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
}
<div id="mydiv">
<div id="mydivheader">click OR drag</div>
</div>
mouseupandclickare different events (even though both are caused by the same interaction!), so stopping one doesn't affect the other.Event order
(An explanation to Bujaq's answer:)
An event's propagation path is determined before propagation. That means adding/removing
clicklisteners in anotherclicklistener won't have any effect on the current event's path.However, different event types can affect each other, even those from the same event source, e.g. a mouse click. Events are run in a fixed order; for mouse events,
mouseupruns beforeclick.Taking the event loop into consideration: Calls to the event handlers are queued, so tasks added via
setTimeout()will be run later. That is also the reason why 0 ms is enough, too.That means, adding the
onclicklike that will only have an effect after the pending events have been handled.Conditional call
You want to only accept
clickevents if no dragging occured. That means we need a way to tell if dragging occured.Dragging has always occured if a
mousemoveevent happened after amousedownevent.Since a
clickevent is fired even when dragging, we can call the "actual" listener only when no dragging occured:Capture and stop
Alternatively to conditionally calling the
clicklistener, we can just stop the event from propagating.We need to stop the event before it reaches the expected listener. This can be done in two ways:
Both ways require the use of
addEventListener()to attach the listeners, which is the preferred way. Theoneventproperties and especially inline event attributes are generally discouraged.In the end we want to make use of the event flow. Example:
If we ensure that the propagation-stopping listener is called before the "intended" listener, we don't have to remove and reattach any listeners at all:
Apart from the three sections above, I want to demonstrate one more thing:
Event delegation
As seen in the event flow, an event goes through multiple phases:
Events propagate down to and up from their target. That means we can use a single listener on an ancestor for multiple targets. This is called event delegation.
Assuming that only one element can be dragged at once, we can attach a single listener on an ancestor, where we'll stop propagation when applicable.
Under these conditions, we can make elements automatically behave as wished simply by adding a class:
Sidenote: Notice how the deeper elements don't need to be aware of the capturing. This allows for easy component-based development.