Question: How to force a function to use the value of a variable when it's given rather than the cur

J

joltman

OK, this is kind of hard to explain, so I'll do my best:
I have a form where I have a row where there could be multiple entries,
so I have a link where it will dynamically add another row like it, and
this can happen as many times as you click on the link. This row
consists of 2 drop-down boxes. Depending on the selection of the first
drop-down box, the second drop-down box is either disabled or enabled.
The problem is on these dynamically created rows. Here is the code for
the dynamically created first drop-down:

var cell = row.insertCell(0);
var elSelect = document.createElement('select');
elSelect.setAttribute('name','country[' + regionNumber + ']');
elSelect.setAttribute('id','country[' + regionNumber + ']');
elSelect.setAttribute('onchange','changeCountry(regionNumber)');

regionNumber is a variable that gets 1 added to it every time this
function runs.
As you can see, there is an onchange event handler. The problem is if I
make the onchange occur, it uses the current value of regionNumber, but
I want it to use the value that regionNumber was when that setAttribute
code ran.
Can anyone help me? If I need to further explain, please tell me so.
 
A

ASM

joltman a écrit :
regionNumber is a variable that gets 1 added to it every time this
function runs.
As you can see, there is an onchange event handler. The problem is if I
make the onchange occur, it uses the current value of regionNumber, but
I want it to use the value that regionNumber was when that setAttribute
code ran.
Can anyone help me? If I need to further explain, please tell me so.

var cell = row.insertCell(0);
var elSelect = document.createElement('select');

I ask myself if it wouldn't be better this way :

elSelect.setAttribute('name',country[regionNumber]);
elSelect.setAttribute('id',country[regionNumber]);
elSelect.setAttribute('onchange','changeCountry('+regionNumber+')');

or
var selName = country[regionNumber];
elSelect.setAttribute('name',selName);
elSelect.setAttribute('id',selName);
elSelect.onchange = 'changeCountry('+regionNumber+');';
 
R

RobG

joltman said:
OK, this is kind of hard to explain, so I'll do my best:
I have a form where I have a row where there could be multiple entries,
so I have a link where it will dynamically add another row like it, and
this can happen as many times as you click on the link. This row
consists of 2 drop-down boxes. Depending on the selection of the first
drop-down box, the second drop-down box is either disabled or enabled.
The problem is on these dynamically created rows. Here is the code for
the dynamically created first drop-down:

var cell = row.insertCell(0);
var elSelect = document.createElement('select');
elSelect.setAttribute('name','country[' + regionNumber + ']');
elSelect.setAttribute('id','country[' + regionNumber + ']');
elSelect.setAttribute('onchange','changeCountry(regionNumber)');

regionNumber is a variable that gets 1 added to it every time this
function runs.
As you can see, there is an onchange event handler. The problem is if I
make the onchange occur, it uses the current value of regionNumber, but
I want it to use the value that regionNumber was when that setAttribute
code ran.
Can anyone help me? If I need to further explain, please tell me so.

What you have discovered are closures, there is an article on them here:

<URL:http://www.jibbering.com/faq/faq_notes/closures.html>

Essentially what is happening is that regionNumber in the onclick event
keeps a reference back to regionNumber in the function rather than
inserting the value.

You can 'fix' the issue by getting the regionNumber from the element id,
or by adding the onclick outside the scope of the current function:

elSelect.name = 'country[' + regionNumber + ']';
addOnchange(elSelect, regionNumber);
...

and addChange() goes something like:

function addChange(el, n)
{
el.onchange = function() {changeCountry(n);};
}


I don't pretend to fully understand closures, but below is an example of
how they work. addTable() uses a loop to create some rows in a table
using a counter 'i'.

'i' is used to generate a unique ID for each row, but also in an
anonymous function attached to the onclick attribute. When setting the
value of the ID attribute, the value of i is appended to the ID and
'sticks'. But when it is used in the anonymous function, it retains its
reference back to the original i in the addTable() function.

You can 'fix' this by adding the anonymous function outside the scope of
the addTable() function - addTable2() (which is virtually identical to
addTable()) does that by using the addClick() function. It passes an
element reference and the value of i which is then taken beyond the
scope of the original addTable2() function.

The addClick adds a function that is identical to the one added by
addTable(), but the scope of i is different.

There are probably better ways to do this.



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Closure demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<style type="text/css">

..tRed { border: 1px solid red;}
..tBlue {border: 1px solid blue;}

</style>
<script type="text/javascript">

function addTable(elID)
{
var el = document.getElementById(elID);
if ( !el ) return;

var oTable = document.createElement('table');
var oTbody = document.createElement('tbody');
var oTR, oTD;
for (var i=0; i<3; i++ ){
oTR = document.createElement('tr');
oTD = document.createElement('td');
oTD.id = 'cell-' + i;
oTD.onclick = function() {
alert('The id is ' + this.id
+ '\nthe value of i is ' + i);
};
oTD.appendChild(document.createTextNode(oTD.id));
oTR.appendChild(oTD);
oTbody.appendChild(oTR);
}
oTable.className = 'tRed';
oTable.appendChild(oTbody);
el.appendChild(oTable);
}

function addTable2(elID)
{
var el = document.getElementById(elID);
if ( !el ) return;

var oTable = document.createElement('table');
var oTbody = document.createElement('tbody');
var oTR, oTD;
for (var i=0; i<3; i++ ){
oTR = document.createElement('tr');
oTD = document.createElement('td');
oTD.id = 'cell-' + i;
addClick(oTD, i);
oTD.appendChild(document.createTextNode(oTD.id));
oTR.appendChild(oTD);
oTbody.appendChild(oTR);
}
oTable.className = 'tBlue';
oTable.appendChild(oTbody);
el.appendChild(oTable);
}

function addClick( el, i)
{
el.onclick = function() {
alert('The id is ' + this.id
+ '\nthe value of i is ' + i);
};
}

</script>
</head>
<body>
<input type="button" value="Add table red" onclick="
addTable('xx');
">
<input type="button" value="Add table 2 blue" onclick="
addTable2('xx');
">

</div>
<div id="xx"></div>

</body></html>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,733
Latest member
LonaMonzon

Latest Threads

Top