William
William

Reputation: 976

Why Javascript event handler is called twice?

When I add an event handler to element of a class as follows:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    var divs = document.getElementsByClassName("class1");
    var onclick = function() {
      alert("clicked");
    }
    for (var i = 0; i < divs.length; i++) {
      divs[i].addEventListener("click", onclick);
    }
  </script>
</body>

</html>

The alert window is popped up twice if I click on the div element. But if I use the following code, the alert window is only popped up once.

<html>

<head>
  <title>test</title>
</head>

<body>
  <div class="class1" id="div1">div1</div>
  <script>
    var divs = document.getElementsByClassName("class1");
    var onclick = function() {
      alert("clicked");
    }

    divs.addEventListener("click", onclick);
  </script>
</body>

</html>

The following code also pops up the alert window twice:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    var div = document.getElementById("div1");
    var onclick = function() {
      alert("clicked");
    }
    div.addEventListener("click", onclick);
  </script>
</body>

</html>

I wonder why the event handler is called twice, regardless I use addEventListener("click",onclick, true); or addEventListener("click",onclick,false);

I use Firefox browser.

Upvotes: 1

Views: 3897

Answers (3)

Fabio Mariano
Fabio Mariano

Reputation: 11

The only solution that worked for me was to force that the addEventListener to be called once.

Like:

   if (!window.onClickListenerAdded) {
      const onClickListener = (event) => {
        alert("clicked");
      };
      window.removeEventListener('click', onClickListener);
      window.addEventListener('click', onClickListener);
      window.onClickListenerAdded = true;
    }

Upvotes: 0

mplungjan
mplungjan

Reputation: 177786

Why loop at all. Apart from the name (you overwrite the native onclick) issue, why not just add once? You have only one div with a unique ID.

Using an anonymous function makes it even safer not to accidentally use a native function name

const div = document.getElementById("div1");

div.addEventListener("click", () => {
  alert("clicked");
});
<div class="class1" id="div1">div1</div>

NOTE: Be careful using anonymous functions in a loop though. I never do so we are safe here

If you have more than one element to use the same event handler, I always recommend to delegate

document.getElementById("container").addEventListener("click", (e) => {
  const div = e.target.closest("div");
  if (div && div.matches(".class1")) {
    alert(div.id + " clicked");
  }
});
<div id="container">
  <div class="class1" id="div1">div1</div>
  <div class="class1" id="div2">div2</div>
</div>

Upvotes: 2

JLRishe
JLRishe

Reputation: 101662

This is happening because your onclick variable is a global variable, and that means you are essentially doing this when you assign the function to onclick:

window.onclick = function () {
    alert('click');
};

So you are adding the event listener to your divs, and window, and when you click the div, it is firing once on the div, and once on the window.

To avoid this, use an iife to shield your variables from the global scope:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    (function () {
        var divs = document.getElementsByClassName("class1");
        var onclick = function() {
          alert("clicked");
        }
        for (var i = 0; i < divs.length; i++) {
          divs[i].addEventListener("click", onclick);
        }
    })();
  </script>
</body>

</html>

Upvotes: 4

Related Questions