Sergi
Sergi

Reputation: 1240

Event delegation and data attribute, null when clicking on element's text

I have a main div with some inner divs that have a data-value assigned. I don't know if it's because I'm using Bootstrap or the div structure, but when I click in the actual number(as in, the centre of the button) I get "null", clicking outside the number, gives the desired result. I tried putting the number inside a p tag and assigning the data value there but then I get "null" for the whole button.

How can I click on the text inside of the divs and get their value as well?

You can see the actual problem here (ignore operand buttons, 7 always return null as I was running tests):

https://jsfiddle.net/chuLmpoy/

HTML

<div class="container">

    <div class="row output">
      <div class="col-xs-12">
        <div>
          <p id="totalNumber"> <strong> </strong> </p>
        </div>
      </div>
      <!--col-xs-12-->
    </div>
    <!--rowOutput-->

    <div class="row1">
      <div class="col-xs-3 transparent"> <strong> 7 </strong> </div>
      <div class="col-xs-3 transparent"><strong> 8 <strong></div>
    <div class="col-xs-3"><strong> <- <strong></div>
    <div class="col-xs-3"><strong> C <strong></div>
  </div><!--row1-->


  <div class="row1">
    <div class="col-xs-3 number"> <p data value="7"><strong>7 </strong> </p></div>
      <div class="col-xs-3 number" data-value="8"><strong> 8 <strong></div>
    <div class="col-xs-3 number" data-value="9"><strong> 9 <strong></div>
    <div class="col-xs-3"><strong> / <strong></div>
  </div><!--row1-->

   <div class="row1">
    <div class="col-xs-3 number"data-value="4"><strong> 4 </strong> </div>
      <div class="col-xs-3 number" data-value="5"><strong> 5 <strong></div>
    <div class="col-xs-3 number" data-value="6"><strong> 6 <strong></div>
    <div class="col-xs-3"><strong> * <strong></div>
  </div><!--row1-->

      <div class="row1">
    <div class="col-xs-3 number" data-value="1"><strong> 1 </strong> </div>
      <div class="col-xs-3 number" data-value="2"><strong> 2 <strong></div>
    <div class="col-xs-3 number" data-value="3"><strong> 3 <strong></div>
    <div class="col-xs-3"><strong> - <strong></div>
  </div><!--row1-->

       <div class="row1">
    <div class="col-xs-3 number"  data-value="0"><strong> 0 </strong> </div>
      <div class="col-xs-3"><strong> . <strong></div>
    <div class="col-xs-3"><strong> + <strong></div>
    <div class="col-xs-3"><strong> = <strong></div>
  </div><!--row1-->

  </div><!--container-->

</body>

JS

"use strict";


const numbers = document.querySelector(".container");

numbers.addEventListener("click", getEachValue);

function getEachValue(e){

  let clickedValue = e.target.getAttribute('data-value');
  console.log(clickedValue);
  }

Upvotes: 1

Views: 1212

Answers (2)

user1106925
user1106925

Reputation:

e.target is the strong element. You'll need to check for that and use .parentNode to traverse up to its parent.

let button = e.target.nodeName === "STRONG" ? e.target.parentNode : e.target
let clickedValue = e.target.getAttribute("data-value")

Or better yet, ditch the strong element altogether, and style it with CSS.

Also note that many of your strong closing tags are missing the /.


In general, it can be useful to have a function that traverses up from an element in search of an ancestor that matches a selector.

function up(el, sel, stopEl) {
  while ((el = el.parentElement) && !el.matches(sel)) {
    if (stopEl && el === stopEl) {
      return null
    }
  }

  return el
}

This function expects an element and a selector, and from the element will traverse up the ancestors, returning the first ancestor that matches the selector.

There's also an optional third argument that you can pass to have the traversal stop when it reaches a certain element. This can be useful if you don't want to go past the element to which a handler is bound.

In your case, you could use it like this:

let button = up(e.target, "div[data-value]", this)

Upvotes: 2

Michal Tak&#225;č
Michal Tak&#225;č

Reputation: 1055

The click event target is based on position of your click, so it depends if you click on strong element or on div.

The solution is make sure all possible cases for click are covered by condition, that if you click on strong, you will read data attribute of parent node, when clicked on div, you directly read the attr from div etc.

This gets quite complicated when you have multiple nesting in your element.

In your case, the easiest thing to do is get rid of the strong and use styling in CSS.

Upvotes: 1

Related Questions