Reputation: 454
First of all - I'm a noob. Sorry if this question is basic enough. Second - I tried to search and as I can see I applied the solution as instructed in other posts.
With that being said... I have three sets of DIVs. Each set consists on 2 Divs(one inside another). On the OUTER div there's a function that is saying to make a border if it's clicked.
To see the error:
The code is suppose to make a border only in the outer.
HTML
<html>
<head>
<title>Event Propagation</title>
<meta charset="UTF-8" />
</head>
<body onload="onLoad()">
<!--Squares 1-->
<div style="display:inline-block">
<div class="outer" style="height: 100px; width: 100px;">
Outer
<div class="inner" style="height: 50px; width: 50px;margin:20px">
Inner
</div>
</div>
</div>
<!--Squares 2-->
<div style="display:inline-block">
<div class="outer" style="height: 100px; width: 100px;">
Outer
<div class="inner" style="height: 50px; width: 50px;margin:20px">
Inner
</div>
</div>
</div>
<!--Squares 3-->
<div style="display:inline-block">
<div class="outer" style="height: 100px; width: 100px;">
Outer
<div class="inner" style="height: 50px; width: 50px;margin:20px">
Inner
</div>
</div>
</div>
</body>
</html>
The JS
<script>
function onLoad(){
const elOuter = document.querySelectorAll(".outer")
elOuter.forEach(element=>{
element.addEventListener('click', fnChangeColor,false)
})
}
function fnChangeColor(e){
e.target.style.border="1px solid black"
if (e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
}
</script>
FYI - I solved the question creating events to the children attributing the e.stopPropagation on them. That worked. But I know that's not the best approach. If I have a div with 100 divs inside, that'll be a hell on earth.
Upvotes: 4
Views: 3135
Reputation: 454
In this case we have one outer div - the parent, and the inner div - the children.
So - the issue to understand here is:
target: Who triggered the event. currentTarget: the element that has the function set in.
When clicking the inner div, you are clicking the children - but the element that has the function is the parent. So - the function should change the currentTarget (the outer div), not the target (that's the inner div that was clicked).
Just had to change
e.target.style.border="1px solid black"
with
e.currentTarget.style.border="1px solid black"
Upvotes: 0
Reputation: 22265
this is because when you click on "Inner" e.target element is "Inner", not "Outer".
What you do seem to me to a try of understanding event delegation, do it this way:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>xxx</title>
<style>
body > div { display:inline-block; }
.outer { height: 100px; width: 100px; background: lightgrey; }
.inner { height: 50px; width: 50px;margin:20px; background: lightblue; }
.bordering { border: 1px solid black; }
</style>
</head>
<body>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<script>
document.body.onclick= e => {
if (!e.target.matches('.outer')) return // ignore other click events
e.target.classList.toggle('bordering')
}
</script>
</body>
</html>
or this way
document.querySelectorAll('.outer').forEach(el=>{
el.onclick=e=>{
// console.log(e.target.className)
if (!e.target.matches('.outer')) return // ignore other click events
e.target.classList.toggle('bordering')
}
})
In your code, there is only one event used and no way for any propagation.
when the user click on a .inner
the event append on the .inner
element an never on the .outer
.
it's like a bubble following it's a bottom up way, not the reverse.
when the bubble finds a target code (an avent listener), there is no more propagation and the bubble burst.
If you want to see an event propagation you have to set 2 event listeners ( an that mean 2 bubles).
You can see that by adding a console.log(e.target.className) like here:
document.querySelectorAll(".outer, .inner") // => 6 event listeners
.forEach(el=>{ el.addEventListener('click', getClick , false) })
var counter = 0
function getClick(e)
{
console.log( `${++counter} - event listener is on : ${e.currentTarget.className}
clicked element is : ${e.target.className} `)
}
cClear.onclick=_=>{ counter = 0; console.clear() }
body > div { display:inline-block; }
.outer { height: 100px; width: 100px; background: lightgrey; }
.inner { height: 50px; width: 50px;margin:20px; background: lightblue; }
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<button id="cClear">clear console</button>
Upvotes: 3