I am really confused about how preventDefault
function works. In the following example I expect when I drag elem2
, the drag event get cancelled and it does. But why the elem3
drag event is cancelled too when I drag elem3
?
Lets clarify more: When you drag a draggable element , the dragstart
event is fired on that element and all its ancestors. Here when you start dragging elem3
, because event capture is false
, the event bubbles up from elem3
to elem1
(a true
event capture just makes the order of firing reversed). So when you start dragging elem3
the event fires first on elem3
, then elem2
and finally elem1
. When there is no preventDefault
you can drag all three elements. When I add preventDefault
to elem2
, you cannot drag it anymore. But now I cannot drag elem3
either. Why? There is no preventDefault
in elem3
event handler!
const elem1 = document.getElementById("elem1");
elem1.addEventListener("dragstart", elem1EventHandler, false);
const elem2 = document.getElementById("elem2");
elem2.addEventListener("dragstart", elem2EventHandler, false);
const elem3 = document.getElementById("elem3");
elem3.addEventListener("dragstart", elem3EventHandler, false);
function elem1EventHandler(event) {
console.log("elem1");
}
function elem2EventHandler(event) {
console.log("elem2");
event.preventDefault();
}
function elem3EventHandler(event) {
console.log("elem3");
}
#elem1 {
display: block;
position: relative;
width: 200px;
height: 150px;
background-color: deepskyblue;
}
#elem2 {
display: block;
width: 150px;
height: 100px;
background-color: greenyellow;
}
#elem3 {
display: block;
width: 100px;
height: 50px;
background-color: coral
}
<div id="elem1" draggable="true">
<div id="elem2" draggable="true">
<div id="elem3" draggable="true">
</div>
</div>
</div>
2
Answers
Applying
preventDefault()
to adiv
container causes the default behaviour to stop in the container itself and everything inside it, including other containers. In your example,elem3
is nested inelem2
.In this example, you can drag the gray container, since it’s not nested in elem2, but can’t the dark green one, because it is.
You have 2 stages with DOM events
focus
and you don’t use capture). So methods likestopPropagation()
don’t work to stop the default action.preventDefault()
in the propagation stage.By listening on a parent element you actually get both the parent’s events and its children’s events due event propagation/bubbling. To prevent the default action only for the parent check
event.target
. Now you can drag the orange child:Note that if you use
function
as an event handler,this
refers to the DOM element you listen with the handler, so it could be written also like this: