4lackof 4lackof - 2 months ago 5
CSS Question

JS - Child element to not listen to delegated event

In the following snippet you will see a delegated event attached to

document
.

The key thing to note is:

if (e.target.parentNode.id === 'put-stuff-here') {
e.target.classList.toggle('active');
}




function loadItems(target) {
for (var i = 0; i < 10; i++) {
setTimeout(function() {
target.insertAdjacentHTML('beforeend', '<div class="new"><span>Click me!</span>Or click me!</div>');
}, (i * 250));
}
}

document.getElementsByTagName('button')[0].addEventListener('click', function(e) {
loadItems(document.getElementById('put-stuff-here'));
});

document.addEventListener('click', function(e) {
if (e.target.parentNode.id === 'put-stuff-here') {
e.target.classList.toggle('active');
}
});

body {
font-family: 'arial';
display: flex;
flex-flow: column;
}
body > * {
margin-bottom: 16px;
}
#put-stuff-here:before {
display: block;
padding: 8px;
text-align: center;
content: 'Target Location:';
background-color: PapayaWhip;
}
#put-stuff-here {
border: 1px solid black;
}
.new {
background-color: SteelBlue;
padding: 8px;
}
.new span {
border: 1px dotted red;
margin: 8px;
}
.active {
background-color: white;
}

<button>Press Me!</button>
<div id="put-stuff-here">

</div>





As you can see, if you click on the "red-bordered span" it will not work, but if you click on the div it works. I know the reason for this and the "solution" is:

if (e.target.parentNode.id === 'put-stuff-here' || e.target.parentNode.parentNode.id === 'put-stuff-here') {
e.target.classList.toggle('active');
}


This; however, does not fully work, and causes this (click on both the span and then the div):



function loadItems(target) {
for (var i = 0; i < 10; i++) {
setTimeout(function() {
target.insertAdjacentHTML('beforeend', '<div class="new"><span>New!</span></div>');
}, (i * 250));
}
}

document.getElementsByTagName('button')[0].addEventListener('click', function(e) {
loadItems(document.getElementById('put-stuff-here'));
});

document.addEventListener('click', function(e) {
if (e.target.parentNode.id === 'put-stuff-here' || e.target.parentNode.parentNode.id === 'put-stuff-here') {
e.target.classList.toggle('active');
}
});

body {
font-family: 'arial';
display: flex;
flex-flow: column;
}
body > * {
margin-bottom: 16px;
}
#put-stuff-here:before {
display: block;
padding: 8px;
text-align: center;
content: 'Target Location:';
background-color: PapayaWhip;
}
#put-stuff-here {
border: 1px solid black;
}
.new {
background-color: SteelBlue;
padding: 8px;
}
.new span {
border: 1px dotted red;
margin: 8px;
}
.active {
background-color: white;
}

<button>Press Me!</button>
<div id="put-stuff-here">

</div>





There are various other methods I have tested, including:

if (e.target.parentNode.id === 'put-stuff-here' || e.target.parentNode.parentNode.id === 'put-stuff-here') {
e.target.classList.toggle('active') || e.target.parentNode.classList.toggle('active');
}


But they all do not do what I want, which is: when you click anywhere in the
div
, it will toggle the
active
class



I think the solution lies somewhere event bubbling, but I have not been able to find a way to utilize this. Is there a way for child events to "ignore" event handlers on (non-)delegated events?


A jsfiddle for this can be found here.

P.S. I know another way to do this is:

if (e.target.classList.contains('new') || e.target.parentNode.classList.contains('new')) {
e.target.classList.toggle('active');
}


and all the other variations, etc. but that runs into the same problem that I list above.

Answer

You can use pointer-events:

The CSS property pointer-events allows authors to control under what circumstances (if any) a particular graphic element can become the target of mouse events.

.new > * {
  pointer-events: none;
}

function loadItems(target) {
  for (var i = 0; i < 10; i++) {
    setTimeout(function() {
      target.insertAdjacentHTML('beforeend', '<div class="new"><span>Click me!</span>Or click me!</div>');
    }, (i * 250));
  }
}

document.getElementsByTagName('button')[0].addEventListener('click', function(e) {
  loadItems(document.getElementById('put-stuff-here'));
});

document.addEventListener('click', function(e) {
  if (e.target.parentNode.id === 'put-stuff-here') {
    e.target.classList.toggle('active');
  }
});
body {
  font-family: 'arial';
  display: flex;
  flex-flow: column;
}
body > * {
  margin-bottom: 16px;
}
#put-stuff-here:before {
  display: block;
  padding: 8px;
  text-align: center;
  content: 'Target Location:';
  background-color: PapayaWhip;
}
#put-stuff-here {
  border: 1px solid black;
}
.new {
  background-color: SteelBlue;
  padding: 8px;
}
.new > span {
  border: 1px dotted red;
  margin: 8px;
  pointer-events: none;
}
.active {
  background-color: white;
}
<button>Press Me!</button>
<div id="put-stuff-here">

</div>

Comments