If you want to assign an event handler to a node that you've created using document.createElement or even one which you have pulled from the document using a getElementById or getElementsByTagName you can. If you need to use a parameter to the function you use as a handler, you run into trouble.
The simplest example, and one which this technique is particularly well suited for is if you want the basic functionality of passing "this" as the parameter to an event handler. But the technique below can be used to define any parameter that you know about at the time you are creating the node. That still leaves something to be desired over just assigning a function with a variable as a parameter but it's a big step up from nothing.
OK, say you want to have an event handler that echoes the innerHTML property of whatever it's attached to.
When writing static HTML and JS event handlers you'd expect this to work:
<script>
function myH (thing){
alert(thing.innerHTML);
}
<script>
<a href="#" onclick="myH(this);">static; works</a>
and it does. You might also expect this to work:
<script>
var a = document.createElement('a');
a.setAttribute('href','#');
a.innerHTML="dynamic; doesn't work";
a.onclick = myH;
</script>
But it doesn't. Neither does:
<script>
var a = document.createElement('a');
a.setAttribute('href','#');
a.innerHTML="dynamic; doesn't work";
a.onclick = myH(a);
</script>
In the first case onclick does get set to myH but when clicked, myH has no "thing", and in the second, myH gets executed on the spot and onclick gets the return value of myH assigned to it. Not really useful.
Here's the code that makes it work. Given a place to hang the hat:
<div id="1"></div>
<div id="2"></div>
<script>
//just to prove this doesn't work
var a = document.createElement('a');
a.setAttribute('href','#');
a.innerHTML="dynamic; doesn't work";
a.onclick = myH;
document.getElementById('1').appendChild(a);
function myH (thing){
alert(thing.href);
}
a = document.createElement('a');
a.setAttribute('href','#');
a.innerHTML="dynamic; will work";
function bindMe (thing){
var temp = thing;
return function(){
myH(temp);
}
}
a.onclick = bindMe(a);
document.getElementById('2').appendChild(a);
function myH (thing){
alert(thing.innerHTML);
}
</script>
What's going on is that bindMe creates a local variable scope that the anonymous reference it returns is using. The way javascript works in this situation is that the anonymous reference (which becomes the event handler for the onclick) preserves its scope. For a much better explanation see this
explanation of javascript closures.
The code in action:
static; works
Dated: 07/20/2005