2

The following JavaScript has some unwanted behaviour:

<html>
<script>
  function AddEventListener(el, listener)
  {
    el.addEventListener ? el.addEventListener('click', listener) : 
                          el.attachEvent('onclick', listener);
  }

  function Init(parent) 
  {
    var span = document.createElement("span");
    span.innerText = "Span1";

    AddEventListener(span, function() { alert(span.innerText); } ); 
    parent.appendChild(span);
    var span = document.createElement("span");

    span.innerText = "Span2";
    parent.appendChild(span);
  }
</script>
<body onload="Init(document.getElementById('drop'));">
  <div id='drop'></div>
</body>
</html>

If you click on Span1, Span2 is shown in the alert window. I understand why: javascript variable scope. But I don't know how to solve it.

Some context: I used this.innerHTML which works fine except in IE8. this points to the window in IE8, not to the parent of the event listener.

3 Answers 3

2

Instead of using a global variable in your click callback, you can use the event parameter that is being passed to every event you register, and then use its event.target parameter to get the DOM element that participated in the event.

For that, you may change your event listener registering to: AddEventListener(span,function(event) {alert((event.target ? event.target : event.srcElement).innerText);});

I've set up an example of it using your code here: http://jsfiddle.net/dvirazulay/fTa6T/1/

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, that's indeed a good one. A minor extension will make it work on IE8 too: AddEventListener(span,function() {alert((event.target?event.target:event.srcElement).innerText);});
This won't work in IE8, and in cases where there are nested elements, the .target could be one of those instead of the element to which the handler is bound.
@Tin: added in the answer to support IE8
2

You can return a function instead of just declaring one, but I like @Dvir Azulay suggestion better:

function CreateAlert(span)
{
    return function() { alert(span.InnerText); };
}

function Init(parent) 
{
    var span=document.createElement("span");
    span.innerText="Span1";
    AddEventListener(span, CreateAlert(span)); 
    parent.appendChild(span);
    var span=document.createElement("span");
    span.innerText="Span2";
    parent.appendChild(span);
}

Comments

0

Try this: (changed the second definition of span to span2)

<!DOCTYPE html>
<html>
<script>

function AddEventListener(el,listener)
{
  el.addEventListener ? el.addEventListener('click', listener) :     el.attachEvent('onclick', listener);
}

function Init(parent) 
{
 var span=document.createElement("span");
 span.innerText="Span1";
 AddEventListener(span,function() {alert(span.innerText);}); 
 parent.appendChild(span);
 var span2=document.createElement("span");
 span2.innerText="Span2";
 parent.appendChild(span2);
}
</script>
<body onload="Init(document.getElementById('drop'));">
<div id='drop'></div>
</body>
</html>

1 Comment

I know this will work but then I have to ensure all variables used have a unique name in the whole scope. In this simplified example it would be feasible...

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.