Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript events and bubbling

I have the following (simplified) markup code:

<div id="container">
    <div data-value="1">
        <span>Click me 1</span>
    </div>
    <div data-value="2">
        <span>Click me 2</span>
    </div>
</div>
<div id="messages"></div>

I want to take advantage of bubbling by attaching an event listener only on the #container, and get the clicked children's data-value.

document.getElementById('container').addEventListener('click', function(e){
    document.getElementById('messages').innerHTML = 'you clicked ' + e.target.dataset.value;
}, false);

Everything works fine if the clicked area is the div area (in red in the fiddle). How can I get the data-value also when the click comes from a children of the div (e.g. click on a blue span) with the data value without changing the event listener?

Here's the fiddle: http://jsfiddle.net/hgLagy31/1/

like image 919
Lorenzo Marcon Avatar asked Sep 28 '22 03:09

Lorenzo Marcon


1 Answers

e.target is the element the user clicked, it is showing undefined since the <span> does not have a data-value attribute. You could go up the tree and find the nearest ancestor that does contain a data-value.

document.getElementById('container').addEventListener('click', function(e) {
  // Find nearest ancestor with data-value defined
  var node = e.target;
  while (!node.dataset.value) {
    node = node.parentNode;
  }
  document.getElementById('messages').innerHTML =
    'you clicked ' + node.dataset.value;
}, false);
#container > div {
  background: red;
}
#container > div > span {
  background: blue;
  color: white;
}
<div id="container">
  <div data-value="1">
    <span>Click me 1</span>
  </div>
  <div data-value="2">
    <span>Click me 2</span>
  </div>
</div>
<div id="messages"></div>

To make this more robust, you could check whether node is undefined before continuing in the while loop and exit if so:

while (!node.dataset || !node.dataset.value) {
  node = node.parentNode;
  if (!node) {
    document.getElementById('messages').innerHTML =
        'Could not find data-value';
    return;
  }
}

document.getElementById('container').addEventListener('click', function(e) {
  // Find nearest ancestor with data-value defined
  var node = e.target;
  while (!node.dataset || !node.dataset.value) {
    node = node.parentNode;
    if (!node) {
      document.getElementById('messages').innerHTML = 'Could not find data-value';
      return;
    }
  }
  document.getElementById('messages').innerHTML =
    'you clicked ' + node.dataset.value;
}, false);
#container > div {
  background: red;
}
#container > div > span {
  background: blue;
  color: white;
}
<div id="container">
  <div data-value="1">
    <span>Click me 1</span>
  </div>
  <div data-value="2">
    <span>Click me 2</span>
  </div>
  <div>
    <span>Click me 3</span>
  </div>
</div>
<div id="messages"></div>
like image 81
Daniel Imms Avatar answered Oct 05 '22 08:10

Daniel Imms