Afelip
Afelip

Reputation: 61

How to make a condition for event 'click' inside/outside for multiple divs?

I have a html And js as below :

document.addEventListener('click', myFunction())

function myFunction(e) {
  let inputs = document.querySelectorAll('.my-element');
  let m = inputs.forEach((el) => el.contains(e.target));
  if (!m) {
    console.log('Element');
  }
}
<div class="my-element" style: "width:100px; height: 100px">
</div>
<div class="my-element" style: "width:100px; height: 100px">
</div>
<div class="my-element" style: "width:100px; height: 100px">
</div>

The problem is, the condition works even if I click inside the target. I need that the condition works only if I click outside of the elements. What my mistake is?

Upvotes: 2

Views: 113

Answers (3)

If you want a click event to fire only if it isn't over certain elements you have to check if the event target is not the same as any it those elements

You almost have it except you are setting the value of m to a forEach which always returns undefined, then checking !m which will always be true

Just make a new array from the node list and set m to the .find value instead, so altogether

document.addEventListener('click', myFunction)

function myFunction(e) {
  let inputs = document.querySelectorAll('.my-element');
  let titles = document.querySelectorAll('.my-title');
  let m = Array.apply(0,inputs).find((el) => el.contains(e.target));
  if (!m) {
    console.log('Element');
  }
}

Upvotes: 1

Karan
Karan

Reputation: 12629

Remove () from myFunction in document.addEventListener('click', myFunction()) just use document.addEventListener('click', myFunction).

You can use Element.matches() with target as e.target.matches('.my-element') and verify that it is the one you want. matches will take selector as parameter.

Try in below sample, when you click on label or input it won't log anything. When you click other part of div then it will log.

document.addEventListener('click', myFunction);

function myFunction(e) {
  //let inputs = document.querySelectorAll('.my-element');
  //let titles = document.querySelectorAll('.my-title');
  //let m = inputs.forEach((el) => el.contains(e.target));
  if (e.target.matches('.my-element')) {
    console.log('Element', e.target.innerText);
  }
}
<div class="my-element" style: "width:100px; height: 100px">
  <label>abcd</label>
</div>
<div class="my-element" style: "width:100px; height: 100px">
<input type='text' value='input' />
</div>
<div class="my-element" style: "width:100px; height: 100px">c
</div>

Upvotes: 0

Ilijanovic
Ilijanovic

Reputation: 14904

Here:

Because inputs is an nodelist you need to convert it to an array.

I have done i here with the spread operator ...

You can also do it with Array.from, [].concat(inputs)

Then you filter the array for your e.target and check if the length is 0.

document.addEventListener('click', myFunction)

function myFunction(e) {
  let inputs = document.querySelectorAll('.my-element');
  let m = [...inputs].filter(el => el === e.target);
  if (!m.length) {
    console.log('Element');
  }
}
<div class="my-element" style="background: black;margin: 10px;width:100px; height: 100px">
</div>
<div class="my-element" style="background: black;margin: 10px;width:100px; height: 100px">
</div>
<div class="my-element" style="background: black;margin: 10px;width:100px; height: 100px">
</div>

Upvotes: 1

Related Questions