4

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! :-)

2 Answers 2

8

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);
};
Sign up to request clarification or add additional context in comments.

3 Comments

Ahh. So effectively total is becoming like a variable pointer, much like in C++ variable*?
Actually, it's being copied into a local scope. If it were a pointer, then it would change both inside and outside of scope, which would bring you back to your original problem.
@Gary Matt's example is correct, here's a little terminology for you. You were running into your specific problem because of something known as "closure" (jibbering.com/faq/faq_notes/closures.html), which is a great and powerful feature of JavaScript. What Matt has shown you is how to get around the closure property (which sometimes gets in the way as you have seen) using anonymous functions and a technique known as currying. See ejohn.org/blog/partial-functions-in-javascript and stackoverflow.com/questions/1413916.
3

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));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.