473,433 Members | 1,790 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,433 software developers and data experts.

Problem with dynamically set onclick

abs
Hi everyone.

Please, check my test code here: http://skocz.pl/jstest . The trouble is
that no matter which span element I click, it alerts '3' and I'm wondering
why not '1' for the first span, '2' for second and '3' for third ? Anybody
has any idea ?

Best regards,
ABS
Jan 2 '07 #1
7 7463
abs wrote:
Hi everyone.

Please, check my test code here: http://skocz.pl/jstest . The trouble is
that no matter which span element I click, it alerts '3' and I'm wondering
why not '1' for the first span, '2' for second and '3' for third ?
The values should be 0, 1 and 2.

Anybody has any idea ?
You have discovered closures - the code of interest is:

function setOnclicks() {
spans = document.body.getElementsByTagName('span')
for(i=0; i<spans.length; i++) {
span = spans[i]
span.onclick = function() {testfunction(i)}
}
}

i here forms a closure back to i in the function (which you've created
as a global, but even if you'd made it local you'd still get the same
result). When the loop finishes, the value of i is 3, so all the
onclicks show 3.

Always declare variables with var, particularly for counters like i
inside functions. Some candidates for a solution are:
function setOnclicks() {
var spans = document.body.getElementsByTagName('span')
for(var i=0; i<spans.length; i++) {
span = spans[i]
span.onclick = new Function('testfunction(' + i + ')');
}
}
But new Function is considered only marginally better than using eval.
Another way to modify the scope chain is:

function setOnclicks() {
var spans = document.body.getElementsByTagName('span')
for(var i=0; i<spans.length; i++) {
span = spans[i]
span.onclick = (function(x){
return function(){testfunction(x)};
})(i);
}
}
However I find that exacerbates IE's memory leak problem with closures
involving DOM elements - it may not be a problem for you in this case.

You can also modify the scope chain by using a function to attach the
handler:

function setOnclicks() {
var spans = document.body.getElementsByTagName('span')
for(var i=0; i<spans.length; i++) {
addOnclick(spans[i], i);
}
}

function addOnclick(el, i){
el.onclick = function(){testfunction(i);};
}
A novel suggestion by Lasse Nielsen[1] uses with:

function setOnclicks() {
var spans = document.body.getElementsByTagName('span')
for(var i=0; i<spans.length; i++) {
span = spans[i]
with ({temp : i}) {
span.onclick = function(){testfunction(temp)};
}
}
}
1. <URL:
http://groups.google.com.au/group/co...0caf593c683e27
>
There are probably other solutions, search the archives for 'onclick
closure'
--
Rob
Jan 2 '07 #2
abs wrote:
Please, check my test code here: http://skocz.pl/jstest . The trouble is
that no matter which span element I click, it alerts '3' and I'm wondering
why not '1' for the first span, '2' for second and '3' for third ? Anybody
has any idea ?
The reason is because all the functions you use in your assignment, all
reference the same variable i. After your assigment, the i changes, and
these functions reflect the change. If one of the functions changed the
value for i, the other would see the same change.

Here's one way to solve this:

function set(i) { return function() {testfunction(i)} };
for(i=0; i<spans.length; i++)
{
span = spans[i]
span.onclick = set(i);
}

This creates a new closure for every invocation, so each sees a
different i.

A somwhat more complex way with the same result, is replacing the inner
function with one that is defined and called in one go:

for(i=0; i<spans.length; i++)
{
span = spans[i]
span.onclick = (function (i) { return function() {testfunction(i)}
})(i);
}

--
Bart.

Jan 2 '07 #3
abs
"RobG" <rg***@iinet.net.auwrote in message
news:45**********************@per-qv1-newsreader-01.iinet.net.au...
The values should be 0, 1 and 2.
Ofcourse :) Sorry.
You have discovered closures - the code of interest is: [...]
Thank you very much for such interesting lesson and for make me conscious
that closures exist :)

Best regards,
ABS
Jan 2 '07 #4
abs
<ba*********@pandora.bewrote in message
news:11**********************@n51g2000cwc.googlegr oups.com...
Here's one way to solve this:
Big thanks for help.

Best regards,
ABS
Jan 2 '07 #5
abs wrote:
Hi everyone.

Please, check my test code here: http://skocz.pl/jstest . The trouble is
that no matter which span element I click, it alerts '3' and I'm wondering
why not '1' for the first span, '2' for second and '3' for third ? Anybody
has any idea ?

Best regards,
ABS
The value of i, which is a global variable, at then end of the for loop
is 3. The invocation, testfunction(i) in the onclick event uses the
current value of i, not the value when the onclick event was
established.
As a side note, the values you want will never be displayed in the
alert box, because the variable i has a range of 0-2; at the first
span, i is 0, then 1, and finally 2. The loop terminates when i
>=spans.length, which in this case, is 3.
There are a number of ways to fix the code to do what you want. Here is
one way:

function setOnclicks()
{
spans = document.body.getElementsByTagName('span')
for(i=0; i<spans.length; i++)
{
span = spans[i]
span.onclick = function () {
var x;
x = i + 1;
return function() {testfunction(x)}
}();
}
}
This code calls a function that returns a function using the current
value of i as the value of a local variable, x. The value of x is bound
at the time the function is executed. When the onclick occurs, the
value of x, created at the time the function was returned, is used in
the invocation of testfunction. This is called a closure, you can find
out more about these things at:

http://jibbering.com/faq/faq_notes/closures.html

Hope this helps.

Jan 2 '07 #6
Bill W wrote on 02 jan 2007 in comp.lang.javascript:
There are a number of ways to fix the code to do what you want. Here is
one way:

function setOnclicks()
{
spans = document.body.getElementsByTagName('span')
for(i=0; i<spans.length; i++)
{
span = spans[i]
span.onclick = function () {
var x;
x = i + 1;
return function() {testfunction(x)}
}();
}
}
Why not make the count an attribute of the span?

function setOnclicks() {
spans = document.body.getElementsByTagName('span');
for(i=0; i<spans.length; i++) {
span = spans[i];
span.nmbr = i + 1;
span.onclick = function() {alert(this.nmbr)};
};
};

Tested in IE7.
--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)
Jan 2 '07 #7
RobG wrote:
<snip>
function setOnclicks() {
var spans = document.body.getElementsByTagName('span')
for(var i=0; i<spans.length; i++) {
span = spans[i]
span.onclick = new Function('testfunction(' + i + ')');
}
}
But new Function is considered only marginally better than using eval.
That would be a matter of opinion. The - eval - function is commonly
abused for tasks that are better done in other ways. The Function
constructor can be similarly abused, but constructing function objects
cannot be an abuse of the Function constructor.
Another way to modify the scope chain is:

function setOnclicks() {
var spans = document.body.getElementsByTagName('span')
for(var i=0; i<spans.length; i++) {
span = spans[i]
Shouldn't - span - be declared as a local variable?
span.onclick = (function(x){
return function(){testfunction(x)};
})(i);
}
}

However I find that exacerbates IE's memory leak problem with closures
involving DOM elements -
<snip>

Closures involving DOM elements are not an issue in IE. Circular chains
of reference including DOM elements provoke the IE memory leak issue.
Closures are just one way if creating such chains, and not always in a
way that is clearly evident.

In this case, after the loop, nulling - span - and - spans - would
ensure that no object on the inner function's scope chain referred to
the elements to which the event handlers had been assigned, and so no
_circular_ chain of references would exist.

Richard.

Jan 2 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: RobG | last post by:
I am trying to dynamically add an onclick to an element, however I just can't get the syntax right. consider the following function: function doClick (evt,x) { // do things with evt and x } ...
4
by: RobG | last post by:
I have a function whose parameter is a reference the element that called it: function someFunction(el) { ... } The function is assigned to the onclick event of some elements in the HTML...
0
by: Diane Yocom | last post by:
I'm very new to ASP.Net and probably jumped in a little over my head, but... I'm trying to create a user control that will control navigation through my site. It's sortof like Amazon.com, where...
0
by: Luis Esteban Valencia | last post by:
Hello I wrote a program with code behind in C# to add row into table dynamically and the program worked very well in .Net Framework 1.1. When I run this program in .Net Framework 2.0 beta...
1
by: mxliron | last post by:
hi all, this code is for a picture viewer. yes, this is my first code and my first piece of programming so i maybe simply be missing some key notions here. the problem is: the nav onclick event...
5
by: stellstarin | last post by:
I have a html where fields are created and added dynamically on the client side. I use the AppendChild() call to create fields dynamically. On submit i try to get the value for all the...
8
by: Samik R. | last post by:
Hello, I am using the innerHTML property of a div placeholder to update the contents, and the HTML is provided from a perl script on the server side. The perl script gets called through AJAX when I...
15
by: anonymousstar | last post by:
Hi All, I have searched the forums to see if I can find an answer to my question but to no avail. I have a form below with a 3 x 3 cell. Each of these cells change from green to yellow if...
5
by: Xu, Qian | last post by:
Hello All, I have some problem by simulating a link click using javascript. The webpage uses a js-library named interface (jQuery like) ------------------------------ <a id="foo" href="#">Try...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.