RAZERZ
RAZERZ

Reputation: 208

Event.target check is happening too fast

NO jQuery

I am currently checking if the user pressed outside an element. However, when console.logging the event.target, I see that one click happen on 2 elements (one is an input element and the other one is a label). The label element is showing first, which results in the function thinking that the press did not happen on the input element and therefore the click occurred outside of the element but that's not true.

The reason I want to check if the press was outside the input element and not the label, is because there are <span>'s and other elements that get triggered when clicking.

My code so far:

document.addEventListener("click", function(event) {checkChecked(event); });

function checkChecked(inputEvent) {
    if(inputElement !== inputEvent.target && !inputElement.contains(inputEvent.target)) {
        console.log("click outside");
    }
}

And the HTML:

<li class="payment-shipping-method checked">
    <h3>
        <input type="radio" name="paymentMethodId" id="payment-method-7-radio" class="payment-method" value="7" checked="">
        <label for="payment-method-7-radio">
            <span class="figure"><b><img src="img" alt=""></b></span>
            <span class="caption">caption<span class="price zero">
            <span class="amount">0</span>
            <span class="currency">&nbsp;kr</span>
            </span><i>caption</i></span>
        </label>
    </h3>
    <div class="description"></div>
</li>

How can I do this?

Upvotes: 1

Views: 348

Answers (2)

Heretic Monkey
Heretic Monkey

Reputation: 12113

I looked into this a bit more, and found this was not as easy as I thought, but still possible. Of note in this edit:

  • I've shortened your addEventListener line a bit. Since checkChecked takes a single event argument like all event handlers, we can just reference it directly.
  • I was trying to use inputEvent.target.closest("label") to get the closest label ancestor of the clicked element, but for some reason that wasn't working in the snippet. I included a quick recreation of the functionality in the getClosest function.
  • I also included a couple of extra logs for when the user clicks the label and when the user clicks the input. You can see from those logs that clicking the label also generates a click event for the input...

document.addEventListener("click", checkChecked);

var inputElement = document.getElementById("payment-method-7-radio");

// For some reason, while I was building this snippet, 
// I found the native Element.closest function was not 
// working, and built this substitute
function getClosest(fromElement, toSelector) {
  if (fromElement.matches(toSelector)) {
    return fromElement;
  }
  if (fromElement === document.documentElement) {
    return null;
  }
  return getClosest(fromElement.parentElement, toSelector);
}

function checkChecked(inputEvent) {

  var closestLabel = getClosest(inputEvent.target, "label");
  if (inputElement !== inputEvent.target && 
      (!closestLabel || closestLabel.getAttribute("for") !== inputElement.id)) {
    console.log("click outside");
    return;
  }
  if (inputElement === inputEvent.target) {
    console.log("clicked element");
  }
  if (closestLabel && closestLabel.getAttribute("for") === inputElement.id) {
    console.log("clicked label");
  }
}
<li class="payment-shipping-method checked">
  <h3>
    <input type="radio" name="paymentMethodId" id="payment-method-7-radio" class="payment-method" value="7" checked="">
    <label for="payment-method-7-radio">
      <span class="figure"><b><img src="img" alt=""></b></span>
      <span class="caption">caption<span class="price zero">
      <span class="amount">0</span>
      <span class="currency">&nbsp;kr</span>
      </span><i>caption</i></span>
    </label>
  </h3>
  <div class="description"></div>
</li>

Upvotes: 1

fethe
fethe

Reputation: 697

you are adding a listener to the document, so the callback will be called on any click

replace the first line with this and don't forget to modify the selector

document.querySelector('yourInputsSelector').addEventListener('click', checkChecked)

Upvotes: 0

Related Questions