... or my script, or my mind, or both?
<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">
<script>
function init() {
var arr = document.getElementsByTagName('DIV');
for (i=0; i<arr.length; i++) {
arr[i].addEventListener(
'click',function(e){myFunction(arr[i],e);},true);
}
}
function myFunction(obj,evt) {
alert(obj.id);
}
</script>
</head>
<body bgcolor="#FFFFFF" onload="init()">
<div id='d1'>Some <a href="javascript:void(0)" id='s1'>link</a></div>
<div id='d2'>Some <a href="javascript:void(0)" id='s2'>link</a></div>
</body>
</html>
The above simply doesn't work - myFunction gets undefined as obj ! But
with a bogus intermediary var it works like a charm:
function init() {
var arr = document.getElementsByTagName('DIV');
var foo = null;
for (i=0; i<arr.length; i++) {
foo = arr[i];
arr[i].addEventListener(
'click',function(e){myFunction(foo,e);},true);
}
}
All the same in IE (with attachEvent). What a hey?
VK - 30 May 2005 12:31 GMT
The mistery is growing... I thought that maybe this way I was working
with a collection object and not with a "blue blood" array, and it
might cause some strange problem. So I did this profoundly idiotic
algorithm just to be 100% sure I'm working with a real global array:
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">
<script>
// Declaring a global array variable:
var glbArray = new Array();
function init() {
var foo = null;
var tmp = document.getElementsByTagName('DIV');
for (i=0;i<tmp.length;i++) {
// filling up the global array from the collection:
glbArray.push(tmp[i]);
}
for (i=0; i<glbArray.length; i++) {
//
glbArray.addEventListener('click',function(e){myFunction(glbArray[i],e);},true);
// ^ NOOP !!! myFunction gets undefined
foo = glbArray[i];
foo.addEventListener('click',function(e){myFunction(foo,e);},true);
// ^ Works like a charm !!!
}
}
function myFunction(obj,evt) {
alert(obj.id);
}
</script>
</head>
<body bgcolor="#FFFFFF" onload="init()">
<div id='d1'>Some <a href="javascript:void(0)" id='s1'>link</a></div>
<div id='d2'>Some <a href="javascript:void(0)" id='s2'>link</a></div>
</body>
</html>
All the same with IE. Any light?
Michael Winter - 30 May 2005 12:38 GMT
> ... or my script, or my mind, or both?
Don't assume that a subject has been, or can be, read in full.
> <script>
The type attribute?
> function init() {
> var arr = document.getElementsByTagName('DIV');
[quoted text clipped - 3 lines]
> }
> }
When a closure is created, it doesn't take a snapshot of the variables
in its scope chain - they remain live. By the time the listener is
invoked, i will 'point' beyond the defined array contents, providing
undefined to myFunction.
With addEventListener, or the on<type> properties, the better approach is:
function init() {
var arr = document.getElementsByTagName('div');
for(var i = 0, n = arr.length; i < n; ++i) {
/* Unless you have a reason to use
* event capturing, don't bother.
*
* The capturing phase should only
* be used to intercept events
* before 'normal' event listeners
* receive the event.
*/
arr[i].addEventListener('click', myFunction, false);
}
}
function myFunction(e) {
/* The this operator will refer
* to the correct DIV element.
*/
alert(this.id);
}
Unfortunately this won't work with Microsoft's attachEvent mechanism
(the this operator isn't set correctly), which is why it's broken and I
never use it.
[snip]
> But with a bogus intermediary var it works like a charm:
No it doesn't.
[snip]
> for (i=0; i<arr.length; i++) {
> foo = arr[i];
The foo variable will always refer to the last DIV element encountered.
Click the first link in your example and this is obvious.
[snip]
Mike

Signature
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Richard Cornford - 30 May 2005 13:31 GMT
<snip>
> function init() {
> var arr = document.getElementsByTagName('DIV');
[quoted text clipped - 3 lines]
> }
> }
The function passed to abbEventListener is executed long after the loop
has finished executing, and when the containing function's local
variable - i - has been incremented beyond the range of the contents of
the - arr - collection.
> The above simply doesn't work - myFunction gets undefined as obj !
Yes, the contents of - arr[arr.length] - are undefined, and - i ==
arr.length - at the end of the loop.
> But
> with a bogus intermediary var it works like a charm:
You really should test these things a bit less superficially before
making that type of statement. The local variable - foo - always
contains a reference to the same DOM element regardless of how many
event listeners were attached, and which is executed.
> function init() {
> var arr = document.getElementsByTagName('DIV');
> var foo = null;
> for (i=0; i<arr.length; i++) {
> foo = arr[i];
This assignment happens - arr.length - times, and the last assignment
sets the value of - foo - that the event handlers will be using.
> arr[i].addEventListener(
> 'click',function(e){myFunction(foo,e);},true);
> }
> }
>
> All the same in IE (with attachEvent). What a hey?
Closures!
<URL: http://jibbering.com/faq/faq_notes/closures.html >
Richard.
VK - 30 May 2005 14:30 GMT
> You really should test these things a bit less superficially
> before making that type of statement.
- Sorry, I really was in rush
I solved the problem by moving the handler assignement out of the loop:
<http://groups-beta.google.com/group/comp.lang.javascript/browse_frm/thread/5f7aa
ccb9f46722f/a5395b4a5dd6472b#a5395b4a5dd6472b>
for (...) {
assignHandler(arr[i]);
}
and:
function assignHandler(obj) {
obj.addEventListener('click', function(e){processClick(obj, e);});
}
I guess it's one of these rather rare situations when the programming
logic goes against the human one.
However it was with closures (I guess there are reasons for them to be
such), it's still "strange" that the program resolves obj at the
function creation time, but refuses to do the same for arr[i] (an array
element).
Richard Cornford - 30 May 2005 15:00 GMT
<snip>
> I guess it's one of these rather rare situations when
> the programming logic goes against the human one.
Speak for yourself. The scope structure in javascript is completely
logical, mechanically and in the perception of (most) humans.
> However it was with closures (I guess there are reasons
> for them to be such), it's still "strange" that the program
> resolves obj at the function creation time, but refuses to
> do the same for arr[i] (an array element).
Just once it would be nice if you would actually go and read the
resources that people refer you to. You might then eventually get into a
position where some of what you think is not twaddle.
Richard.
Lasse Reichstein Nielsen - 30 May 2005 23:14 GMT
> Speak for yourself. The scope structure in javascript is completely
> logical, mechanically and in the perception of (most) humans.
The scope structure is fine and logical, it's just its interaction
with variables that won't feel natural to me. Probably because I
learned closures in a functional language where variables didn't,
well, *vary* very much. :)
/L

Signature
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Lasse Reichstein Nielsen - 30 May 2005 23:12 GMT
> However it was with closures (I guess there are reasons for them to be
> such), it's still "strange" that the program resolves obj at the
> function creation time, but refuses to do the same for arr[i] (an array
> element).
Not so strange. There is only one "i" variable, and all the closures
refer to that one. When it changes its value, it affects all closures.
However, since "obj" is a formal parameter of a function, there is
effectively a new variable for each call. It never varies, and each
closure refers to its own version.
/L

Signature
Lasse Reichstein Nielsen - lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'