alsayed
alsayed

Reputation: 23

Event.target unexpectedly becomes the document in bound event listener function

I want to know if a user selected a size before purchasing clothes,
so I attached an event listener to it's parent container, the selection area.

Product card with selector tiles

Selection Area HTML Markup

If I pass in a bound function as an argument to the event listener,
event.target becomes the document object on click.

if(selectionArea) {
  selectionArea.addEventListener("click", removeWarningStyles.bind(null, event, sizeTiles,warning));
}


Remove warning styles method:

function removeWarningStyles( event, sizeTiles, warning) {

    if(event.target.matches(".size-tile")) { // This becomes the document object. Why?
        for(let tile of  sizeTiles) {
            if(tile.classList.contains("size-tile--not-properly-chosen")) {
                tile.classList.toggle("size-tile--not-properly-chosen");

            }
        }
        warning.style.visibility = "hidden";
        warning.style.opacity = "0";
    }
}


I've even tried to bind event.target and event.currentTarget, but it still doesn't work.



If I write the anonymous function directly into the handler,
it works perfectly. But why?

if(selectionArea) {
   selectionArea.addEventListener("click", (event) => {

      if(event.target.classList.contains("size-tile")) { //becomes size-tile element correctly

        for(let tile of  sizeTiles) {
            if(tile.classList.contains("size-tile--not-properly-chosen")) {
               tile.classList.toggle("size-tile--not-properly-chosen");

           }
        }
        warning.style.visibility = "hidden";
        warning.style.opacity = "0";
     }
 });
}

Upvotes: 2

Views: 245

Answers (1)

StackSlave
StackSlave

Reputation: 10627

You are passing event not as the Event Object is passed to your eventListener, but as an argument of bind, which is useless in this case anyways, because you are binding to the global context and your function does not contain the keyword this.

selectionArea.addEventListener("click", removeWarningStyles.bind(null, event, sizeTiles,warning));

Should really be

selectionArea.addEventListener('click', e=>{
  removeWarningStyles(e, sizeTiles, warning);
});

Actually, I would do like

selectionArea.onclick = e=>{
  removeWarningStyles(e, sizeTiles, warning);
}

because it's easier to remove or overwrite the Event.

PS

Remember that only the Event Object is passed as an argument to an eventListener function, and the this context of an eventListener function is the Object to which the method belongs, as usual, which is the Element in this case. You should also know when calling another function within the eventListening function its this context does not become bound to the Element. Arrow functions, of course work differently, as their this goes up a scope level, where it stays, so binding is pointless with them. In other words, you can't use this.value or this.style.color in an arrow function, like you can in a normal function that is an eventListener.

Upvotes: 1

Related Questions