0

[Final Edit: I feel compel to response as I learned a LOT from this post(mainly through you guys, and I spend more time understanding CSS.. but at the end, I really don't have any good idea how to make this work.. other than really destroying the basic structure of html.. which I didn't want to do. but I did... (for whatever reason #parent>* { color: black } would not work when I click on child)..

Here's what i did but if you now know what I was trying to do.. please see if you can correct me w/ real answer as I feel like this can't be this hackery to get it going.

CSS

.red {
    color: red;
}

div[id*="child"] {
    color: black;
}

div [id*="alterChild"]{
    color: green;

JS

;(function(){

    let parentId = document.getElementById('parent');

    parentId.addEventListener('click', function(e){
        if (e.target.id === 'parent') {
            e.target.className = "red";
        } else {
            e.target.setAttribute("id", "alterChild");
        }
    },false);
})(

HTML

<div id="main">MAIN
    <div id="parent">parent
        <div id="child1">child1</div>
        <div id="child2">child2</div>
        <div id="child3">child3</div>
    </div>
</div

__________END OF FINAL EDIT___________

So I want to fire only on parent when parent is clicked. Below code, it fires on parent + all its children. How can I prevent this? I try w/ stop/prevent both before and after to see if I have any luck.

Please advise.

  • when click on parent, only parent should get class "red". (and not it's children).
  • When any child is clicked, no parent should be red nor any other none clicked child(which was already working).
        <div id="main">MAIN
            <div id="parent">parent
                <div id="child1">child1</div>
                <div id="child2">child2</div>
                <div id="child3">child3</div>
            </div>
        </div>

      ;(function(){

        let parentId = document.getElementById('parent');

        parentId.addEventListener('click', function(e){
            e.stopPropagation();
            e.preventDefault();
            e.target.className = "red";
            e.stopPropagation();
            e.preventDefault();

        },false);
    })()

user3502374
  • 781
  • 1
  • 4
  • 12
  • Possible duplicate of [How do I prevent a parent's onclick event from firing when a child anchor is clicked?](https://stackoverflow.com/questions/1369035/how-do-i-prevent-a-parents-onclick-event-from-firing-when-a-child-anchor-is-cli) – Heretic Monkey Mar 06 '19 at 21:27
  • I have clarified that this is a vanilla javascript question – user3502374 Mar 07 '19 at 01:28
  • what happened to all that comments that I was reading?? it's all gone – user3502374 Mar 07 '19 at 03:24

5 Answers5

1
  • when click on parent, only parent should get class "red". (and not it's children).

The issue here is your CSS style is applying to the children. CSS stands for Cascading Style Sheet where "Cascading" means "applies to children"

After clicking parent you end up with this

.red {
  color: red;
}
<div id="main">MAIN
    <div id="parent" class="red">parent
        <div id="child1">child1</div>
        <div id="child2">child2</div>
        <div id="child3">child3</div>
    </div>
</div>

The fact that the children changed to red has nothing to do with events. It's normal for children to change based on their parent's CSS

If you want to children to not inherit the color of their parent you need to set their color explicitly

.red {
  color: red;
}
#parent>* {  
  color: black;
}

/* these would also work

    div[id^=child]  
    #child1, #child2, #child3
    #parent>div

*/
<div id="main">MAIN
    <div id="parent" class="red">parent
        <div id="child1">child1</div>
        <div id="child2">child2</div>
        <div id="child3">child3</div>
    </div>
</div>

Example:

;
(function() {

  const parentId = document.getElementById('parent');

  parentId.addEventListener('click', function(e) {
    e.target.className = "red";
  }, false);
})()
.red {
  color: red;
}
#parent>* {
  color: black;
}
<div id="main">MAIN
  <div id="parent">parent
    <div id="child1">child1</div>
    <div id="child2">child2</div>
    <div id="child3">child3</div>
  </div>
</div>
  • When any child is clicked, no parent should be red nor any other none clicked child

This is a different issue. When you click any child the event listener will be triggered. e.target will be the element that was actually clicked on so if you clicked a child it will be that child

One way to solve this would be to check the target is the parent.

      const parentId = document.getElementById('parent');

      parentId.addEventListener('click', function(e) {
        if (e.target === parentId) {
          e.target.className = "red";
        }
      }, false);
gman
  • 100,619
  • 31
  • 269
  • 393
  • Ok, so I see your point.. however, when I do this through javascript, children still inherits. – user3502374 Mar 07 '19 at 02:35
  • I am learning so much here.. I continue to look at this right now guys.. thanks for the fantastic points that really points out my completely lack of understanding in css – user3502374 Mar 07 '19 at 02:58
  • this edited post is what I needed: when click on parent, only parent should get class "red". (and not it's children). When any child is clicked, no parent should be red nor any other none clicked child(which was already working). – user3502374 Mar 07 '19 at 03:11
0

There are a few ways to achieve this - one approach would be to examine the id attribute of the currentTarget on the event object for the users click action:

const div1 = document.createElement('div');
div1.className = 'foo';

let mainId = document.getElementById('main');
let parentId = document.getElementById('parent');

parentId.addEventListener('click', function(e) {

  /* Check the id of the currentTarget element to see if it's the "parent" */
  if (e.currentTarget.id === 'parent') {

    /* .. and if so, assing the "red" class */
    e.target.className = "red";
  } else {

    /* ..otherwise, stop event propagation and behaviour */
    e.stopPropagation();
    e.preventDefault();
  }

}, false);
.red {
  background: red;
}

#parent {
  padding: 1rem;
}

#child1,
#child2,
#child3 {
  background: yellow;
}
<body>
  <div id="main">MAIN
    <div id="parent">parent
      <div id="child1">child1</div>
      <div id="child2">child2</div>
      <div id="child3">child3</div>
    </div>
  </div>
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
0

You can check inside the handler whether the element that triggered the event (the target) is the element the handler is bound to (this):

parentId.addEventListener('click', function(e){
  if (e.target === this) {
    e.target.className = "red";
  }
}, false);

https://developer.mozilla.org/en-US/docs/Web/API/Event/target

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    Sure it does: https://jsfiddle.net/9dwzus40/ . Click on any child, color doesn't change. Click on parent, color changes. If that doesn't do what you want then you have to explain your problem better. – Felix Kling Mar 07 '19 at 02:00
  • clarifying my questions now. – user3502374 Mar 07 '19 at 02:05
  • added to main section but here it is: - when click on parent, only parent should get class "red". (and not it's children). - When any child is clicked, no parent should be red nor any other none clicked child(which was already working). – user3502374 Mar 07 '19 at 02:10
  • 1
    The children are not getting the class (you can inspect the DOM). But e.g. text color applies to all text within an element. That’s not a JavaScript but a CSS question then. – Felix Kling Mar 07 '19 at 02:11
  • how can it be css? my css contains this only .green { color: green; } .red { color: red; } div { font-size:100px; } – user3502374 Mar 07 '19 at 02:18
  • As I said, `color` applies to every text node inside an element, not just it child text nodes. It’s how CSS works. Just add `class=red` manually to the parent element in your HTML and you’ll see. – Felix Kling Mar 07 '19 at 02:41
0

You need to stop propagation on children click

<html>

  <head></head>

  <body>
    <div id="main">MAIN
      <div id="parent">parent
        <div id="child1">child1</div>
        <div id="child2">child2</div>
        <div id="child3">child3</div>
      </div>
    </div>
    <script>
      (function() {
        let parent = document.getElementById('parent');
        parent.addEventListener('click', function(e) {
          console.log('parent clicked');
        }, false);
        const children = document.querySelectorAll('#parent>div');
        children.forEach(child => {
          child.addEventListener('click', function(e) {
            console.log('child clicked');
            e.stopPropagation();
          })
        })
      })()

    </script>
  </body>

</html>

https://jsfiddle.net/1xnow7jz/

displayName
  • 986
  • 16
  • 40
0

Check that the current target is the expected element:

document.getElementById("overlay").addEventListener("click", (event) => {
  if (event.target.id === "overlay") {
    document.getElementById("overlay").style.display = "none";
  }
})
tauzN
  • 5,162
  • 2
  • 16
  • 21