skip to Main Content

I’m working on claculator and one of the buttons doesnt responds as rest. First click on it doesnt log to the console. After I click a button for root and then go to square it starts to work. I notice that whe i remove tag then it is working normally

<button class="btn instant-operator btn--squere" data-tab="x2">
          <i>x<sup>2</sup></i>
        </button>
        <button class="btn instant-operator btn--root" data-tab="root">
          √x
        </button>

Some JS code:

function instantOperator(iOperator) {
  console.log(iOperator);
}

    const actionBtn = function (e) {

      const clicked = e.target;
      clicked.classList.remove("btn--clicked");
      void clicked.offsetWidth; // trigger reflow
      clicked.classList.add("btn--clicked");
    
      if (clicked.classList.contains("integer")) {
        integer(clicked);
      } else if (clicked.classList.contains("operator")) {
        operator(clicked);
      } else if (clicked.classList.contains("instant-operator"))
        instantOperator(clicked);
    };
    
    btnsBody.addEventListener("click", actionBtn);

2

Answers


  1. The event.target is normally the element the user clicked on. If you click on the text inside a nested node, the event.target will be the respective node.

    From MDN:

    The read-only target property of the Event interface is a reference to the object onto which the event was dispatched. It is different from Event.currentTarget when the event handler is called during the bubbling or capturing phase of the event.

    b1.onclick = (event) => { console.log(event.target.outerHTML) }
    b2.onclick = (event) => { console.log(event.target.outerHTML) }
    <button id="b1"><i>Click on the text</i></button>
    <button id="b2">Click here <i>not here</i></button>

    You can avoid this, by looking at the event path using event.composedPath():

    b1.onclick = (event) => {
      event.composedPath().forEach(node => {
        if (node.nodeName == "BUTTON") {
          console.log(node.outerHTML);
        }
      });
    }
    <button id="b1"><i>Click on the text</i></button>

    By using css pointer-events: none; for all child elements of a button:

    b1.onclick = (event) => { console.log(event.target.outerHTML) }
    #b1 > * {
      pointer-events: none;
    }
    <button id="b1"><i>Click on the text</i></button>

    Or by using the event.currentTarget or this inside normal functions.

    b1.onclick = (event) => { console.log(event.currentTarget.outerHTML) }
    b2.onclick = function(event) { console.log(this.outerHTML) }
    <button id="b1"><i>Click on the text</i></button>
    <button id="b2"><i>Click on the text</i></button>
    Login or Signup to reply.
  2. use e.currentTarget

    target returns clicked element

    currentTarget returns your event binded element

    look below

    function instantOperator(iOperator) {
      console.log(iOperator);
    }
    
        const actionBtn = function (e) {
    
          const clicked = e.currentTarget;  // here use **currentTarget** like this or use **this**
    //const clicked = this;
          clicked.classList.remove("btn--clicked");
          void clicked.offsetWidth; // trigger reflow
          clicked.classList.add("btn--clicked");
          if (clicked.classList.contains("integer")) {
            integer(clicked);
          } else if (clicked.classList.contains("operator")) {
            operator(clicked);
          } else if (clicked.classList.contains("instant-operator"))
            instantOperator(clicked);
        };
        var btnsBody = document.getElementById('x2');
        btnsBody.addEventListener("click", actionBtn);
    <button id = 'x2' class="btn instant-operator btn--squere" data-tab="x2">
              <i>x<sup>2</sup></i>
            </button>
            <button id='rtx' class="btn instant-operator btn--root" data-tab="root">
              &#x221A;x
            </button>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search