Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript variable scope in addEventListener anonymous function

When clicking on each div it should alert '1' if div 1 was clicked on or '5' if div 2 was clicked on. I have tried to make this code as easy to as possible because this is needed in a much larger application.

<html>
<head>
<style type="text/css">
#div1 { background-color: #00ff00; margin: 10px; padding: 10px; }
#div2 { background-color: #0000ff; margin: 10px; padding: 10px; }
</style>
<script type="text/javascript">

function init()
{
  var total = 1;

  var div1 = document.getElementById('div1'),
      div2 = document.getElementById('div2');

  var helper = function(event, id)
  {
      if (event.stopPropagation) event.stopPropagation();
      if (event.preventDefault) event.preventDefault();

      alert('id='+id);
  }

  div1.addEventListener('click', function(event) { helper(event, total); }, false);

  total += 4;

  div2.addEventListener('click', function(event) { helper(event, total); }, false);

}

</script>
</head>

<body onload="init();">

<div id="div1">1</div>
<div id="div2">2</div>

</body>
</html>

Thanks for your help! :-)

like image 644
Gary Green Avatar asked Dec 29 '22 10:12

Gary Green


2 Answers

The problem is that the event listeners and 'total' both exist in the same scope (init())

The event functions are always going to reference total within the init() scope, even if it is changed after the event functions are declared

To get around this, the event functions need to have a 'total' in their own scope which will not change. You can add another layer of scope using an anonymous function

For example:

(function (total) {
    div1.addEventListener('click', function(event) { helper(event, total); }, false);
}(total));

total += 4;

(function (total) {
  div2.addEventListener('click', function(event) { helper(event, total); }, false);
}(total));

The anonymous functions are passed init()'s current 'total' value as a parameter. This sets another 'total' to the anonymous function's scope, so it does not matter if init()'s total changes or not, because the event function will FIRST reference the anonymous function's scope.

Edit:

Also, you need to place a semicolon after the closing brace of the helper function, otherwise the script will complain that 'event' is undefined.

var helper = function(event, id)
{
  if (event.stopPropagation) event.stopPropagation();
  if (event.preventDefault) event.preventDefault();

  alert('id='+id);
};
like image 118
Matt Avatar answered Dec 31 '22 23:12

Matt


This is almost the same but i think it will be better:

div1.addEventListener('click', function(t){ return function(event) { helper(event, t); }}(total), false);

instead of:

(function (total) {
    div2.addEventListener('click', function(event) { helper(event, total); }, false);
}(total));
like image 30
m4roo Avatar answered Dec 31 '22 23:12

m4roo