Problem with events on dynamically created input fields in internet explorer

T

Thomas

Hi,

I'm having a problem with the dynamically created inputfields in
Internet Explorer.
The situation is the following:
- I have a dynamically created table with a textbox in each Cell.
- It is possible to Add and Delete rows
- Some cells have special attributes (readonly and events)

Here's a snippet of the code:
function addRowToTable(p_vestigingnummer,
p_straat_vest,
p_huisnr_vest,
p_bus_vest,
p_postcode_vest,
p_gemeente_vest,
p_plaats_syscode_vest,
p_vanaf_vest
) {


var tbl = document.getElementById("tablename");
var lastRow = tbl.rows.length;
lastRow--;
v_row++
v_rowid = "row" + v_row;
// if theres no header row in the table, then iteration =
lastRow + 1
var iteration = lastRow;
var row = tbl.insertRow(lastRow);
row.setAttribute("id",v_rowid);

/*.....more cells added here......*/
var CellPostcode = row.insertCell(4);
CellPostcode.setAttribute("nowrap","");
var CellPostcodeTekst = document.createElement("input");
var Anchornode = document.createElement("a");
Anchornode.setAttribute("href","javascript:call_zoekgemeente_byID(\''p_plaats_sys_vest"
+ v_rowid + "\'',\''p_postcode_vest" + v_rowid +
"\'',\''p_gemeente_vest" + v_rowid + "\'')");
var Imagenode = document.createElement("img");
Imagenode.setAttribute("src","/images/list.gif");
Imagenode.setAttribute("border","0");
CellPostcodeTekst.setAttribute("type","text");
CellPostcodeTekst.setAttribute("name","p_postcode_vest_tmp");
CellPostcodeTekst.setAttribute("id","p_postcode_vest" +
v_rowid);
CellPostcodeTekst.setAttribute("size","3");
CellPostcodeTekst.setAttribute("value",p_postcode_vest);
//troubles CellPostcodeTekst.setAttribute("onblur","call_zoekgemeente_byID(\''p_plaats_sys_vest"
+ v_rowid + "\'',\''p_postcode_vest" + v_rowid +
"\'',\''p_gemeente_vest" + v_rowid + "\'')");
CellPostcode.appendChild(CellPostcodeTekst);
Anchornode.appendChild(Imagenode);
CellPostcode.appendChild(Anchornode);

//Cell gemeente
var Cellgemeente = row.insertCell(5);
var CellgemeenteTekst = document.createElement("input");
CellgemeenteTekst.setAttribute("type","text");
CellgemeenteTekst.setAttribute("name","p_gemeente_vest_tmp");
CellgemeenteTekst.setAttribute("id","p_gemeente_vest" +
v_rowid);
CellgemeenteTekst.setAttribute("size","20");
CellgemeenteTekst.setAttribute("value",p_gemeente_vest);
CellgemeenteTekst.setAttribute("READONLY","true"); //troubles
var Cellplaatshidden = document.createElement("hidden");
Cellplaatshidden.setAttribute("type","hidden");
Cellplaatshidden.setAttribute("name","p_plaats_sys_vest_tmp");
Cellplaatshidden.setAttribute("value",p_plaats_syscode_vest);
Cellplaatshidden.setAttribute("id","p_plaats_sys_vest" +
v_rowid);

Cellgemeente.appendChild(CellgemeenteTekst);
Cellgemeente.appendChild(Cellplaatshidden);
}

Now The problem(s) is this:
If you change the textbox "p_postcode" (which is postal code in
english - or something like that) it must invoke a function which
looks up the correct city.
This works fine in Firefox but it doesn't do a damn thing in Internet
Explorer 6. I've allready changed the onchange event to onblur but
that doesn't help.
Second problem is the readonly attribute which doesn't seem to work in
IE.

Now my question is offcourse: Why doesn't it work in Internet
Explorer? Am I dealing with a MS bug here or is there some other
explanation?
Strange thing is that a lot of other attributes work perfectly (but i
don't need those, haha, programming is fun) like disabled, style,
etc....
I's nearly impossible to change the whole code (time is running out)
so I'll have to find a fix here!

anyone have a clue?

Greetz,
Thomas
 
S

Steve Fulton

Thomas said:
Hi,

I'm having a problem with the dynamically created inputfields in
Internet Explorer.
The situation is the following:
- I have a dynamically created table with a textbox in each Cell.
- It is possible to Add and Delete rows
- Some cells have special attributes (readonly and events)
[snip]
CellPostcodeTekst.setAttribute("onblur","call_zoekgemeente_byID(\''p_plaats_sys_vest" [snip]
CellgemeenteTekst.setAttribute("READONLY","true");
[snip]

Now The problem(s) is this:
If you change the textbox "p_postcode" (which is postal code in
english - or something like that) it must invoke a function which
looks up the correct city.
This works fine in Firefox but it doesn't do a damn thing in Internet
Explorer 6. I've allready changed the onchange event to onblur but
that doesn't help.

The problem is that event handler attributes are functions, not strings.
Mozilla browsers parse the string and create a function object, just like
they do when they parse the HTML. IE, on the other hand, expects you to
set the attribute to a Function object; it doesn't parse the string.

Which is correct? Neither, really. According to the W3C DOM specs, the
setAttribute method only accepts a string for the second argument, so
IE isn't compliant. On the other hand, event handlers are special cases
that are handled by a completely separate method using DOM-compliant
clients; they aren't really attributes (which can only be strings) at all.

"addEventListener"
http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget-addEventListener

Unfortunately, IE doesn't follow the spec for adding event handlers to
elements (of course); it has its own proprietary method.

"attachEvent Method"
http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/attachevent.asp

Unless you want to do client capability-sniffing, the cross-browser way
to add event handlers to elements is to avoid the setAttribute menthod
(which is the wrong approach anyway) and the W3C-DOM and MS-proprietary
methods and to use the DOM-0 format:

CellPostcodeTekst.onblur=function(){call_zoekgemeente_byID(...)}
Second problem is the readonly attribute which doesn't seem to work in
IE.

IE wants the attribute to be spelled "readOnly" (with a capital O).
You should also be aware that although Mozilla accepts the value
"READONLY", Opera does not. It also expects the value "readOnly".
Now my question is offcourse: Why doesn't it work in Internet
Explorer? Am I dealing with a MS bug here or is there some other
explanation?

setAttribute isn't really meant to handle event handlers.
Strange thing is that a lot of other attributes work perfectly (but i
don't need those, haha, programming is fun) like disabled, style,
etc....

Other attributes are string values; setAttribute is meant to work with
them.
I's nearly impossible to change the whole code (time is running out)
so I'll have to find a fix here!

anyone have a clue?

Use the DOM-0 method to attach event handlers and use the value
"readOnly" to set the readonly attribute.
 
R

RobG

Thomas said:

Steve has already pointed you in the right direction, I'll just lob a
few extras in...
I'm having a problem with the dynamically created inputfields in
Internet Explorer.
The situation is the following:
- I have a dynamically created table with a textbox in each Cell.
- It is possible to Add and Delete rows
- Some cells have special attributes (readonly and events)

Here's a snippet of the code:
function addRowToTable(p_vestigingnummer,
p_straat_vest,
p_huisnr_vest,
p_bus_vest,
p_postcode_vest,
p_gemeente_vest,
p_plaats_syscode_vest,
p_vanaf_vest
) {


var tbl = document.getElementById("tablename");
var lastRow = tbl.rows.length;
lastRow--;
v_row++
v_rowid = "row" + v_row;
// if theres no header row in the table, then iteration =
lastRow + 1
var iteration = lastRow;
var row = tbl.insertRow(lastRow);
row.setAttribute("id",v_rowid);

All of your 'setAttribute' stuff can be done by accessing the
properties directly. You don't seem to be supporting older browsers,
so I can't see an issue with:

row.id = v_rowid;

And similarly for all the other attributes you set.
/*.....more cells added here......*/
var CellPostcode = row.insertCell(4);
CellPostcode.setAttribute("nowrap","");
var CellPostcodeTekst = document.createElement("input");
var Anchornode = document.createElement("a");
Anchornode.setAttribute("href","javascript:call_zoekgemeente_byID(\''p_plaats_sys_vest"
+ v_rowid + "\'',\''p_postcode_vest" + v_rowid +
"\'',\''p_gemeente_vest" + v_rowid + "\'')");
var Imagenode = document.createElement("img");
Imagenode.setAttribute("src","/images/list.gif");
Imagenode.setAttribute("border","0");
CellPostcodeTekst.setAttribute("type","text");
CellPostcodeTekst.setAttribute("name","p_postcode_vest_tmp");
CellPostcodeTekst.setAttribute("id","p_postcode_vest" +
v_rowid);

Imagenode.src = "/images/list.gif";

// Set all border attributes in one go
Imagenode.style.border = '2px solid red';

// Or just the width:
Imagenode.style.borderWidth = '0px';

CellPostcodeTekst.type = "text";
CellPostcodeTekst.name = "p_postcode_vest_tmp";
CellPostcodeTekst.id = "p_postcode_vest" + v_rowid;
...
CellPostcodeTekst.setAttribute("size","3");
CellPostcodeTekst.setAttribute("value",p_postcode_vest);
//troubles CellPostcodeTekst.setAttribute("onblur","call_zoekgemeente_byID(\''p_plaats_sys_vest"
+ v_rowid + "\'',\''p_postcode_vest" + v_rowid +
"\'',\''p_gemeente_vest" + v_rowid + "\'')");

Untested, but you can attach functions to intrinsic events thusly:

CellPostcodeTekst.onblur = function (){
call_zoekgemeente_byID('p_plaats_sys_vest' + v_rowid,
'p_postcode_vest' + v_rowid,
'p_gemeente_vest' + v_rowid )
};

This way you have access to the variables created in the rest of your
script.
CellPostcode.appendChild(CellPostcodeTekst);
Anchornode.appendChild(Imagenode);
CellPostcode.appendChild(Anchornode);

//Cell gemeente
var Cellgemeente = row.insertCell(5);
var CellgemeenteTekst = document.createElement("input");
CellgemeenteTekst.setAttribute("type","text");
CellgemeenteTekst.setAttribute("name","p_gemeente_vest_tmp");
CellgemeenteTekst.setAttribute("id","p_gemeente_vest" +
v_rowid);
CellgemeenteTekst.setAttribute("size","20");
CellgemeenteTekst.setAttribute("value",p_gemeente_vest);
CellgemeenteTekst.setAttribute("READONLY","true"); //troubles

CellgemeenteTekst.readOnly = true;
var Cellplaatshidden = document.createElement("hidden");
Cellplaatshidden.setAttribute("type","hidden"); [...]

anyone have a clue?

Hope that helps.
 
S

Steve Fulton

Thomas said:
I'm having a problem with the dynamically created inputfields in
Internet Explorer.

Just thought I'd add another setAttribute gotcha. If you want to use it
to set the class of an element, Mozilla expects the attribute to be
called "class" and IE expects it to be called "className"; Opera accepts
either value.

--
Steve

Every gun that is made, every warship launched, every rocket fired
signifies, in the final sense, a theft from those who hunger and are not
fed, those who are cold and are not clothed. -Dwight D. Eisenhower
 
T

Thomas

Untested, but you can attach functions to intrinsic events thusly:

CellPostcodeTekst.onblur = function (){
call_zoekgemeente_byID('p_plaats_sys_vest' + v_rowid,
'p_postcode_vest' + v_rowid,
'p_gemeente_vest' + v_rowid )
};

This way you have access to the variables created in the rest of your
script.


Hope that helps.

This sure helps me a lot! Thank you for your time and answers. But I
have a new problem now: The variable v_rowid always has the newest
value it was assigned, so the last row is always chosen. :s
Can I add parameters to the function so it always works?
 
R

RobG

Thomas said:
This sure helps me a lot! Thank you for your time and answers. But I
have a new problem now: The variable v_rowid always has the newest
value it was assigned, so the last row is always chosen. :s
Can I add parameters to the function so it always works?

Ah, I suspect this is an issue with closure - because the onblur
function still references the variable v_rowid, it stays in existence
even though it was created in the script. When the onblur runs, it
references the existing value, not what it was when the onblur was
created.

If I knew enough about these things I'd probably rabbit on about
scope chains and how to break them, but I don't. I can think of a
few kludgey was to get around it, but I'm sure there's an elegant
solution (and an explanation that will help both our understanding
of the issue) is RC lurking?

Following is a bit of play code as an example of the specific issue.
It adds 5 rows to a table, generating a row id as it goes. The row
id becomes static, but a reference to the same variable from the
onclick function stays dynamic.

Adding multiple sets of rows creates multiple instances of the
persistent variable 'i' - indicating that the lack of closure is also
eating memory - or am I totally off the track?


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

<script type="text/javascript">
function addRows(t){
var cell, i, row, rowId;
for ( i=0; i<5; i++ ){
row = t.insertRow(t.rows.length-1);
row.id = 'row-' + i;
row.onclick = function () {
alert('row-' + i + '\n' + this.id);
};
cell = document.createElement('td');
cell.appendChild(document.createTextNode(i))
row.appendChild(cell);
}
}
</script>
</head>
<body>

<table border="1">
<tbody id="tbodyA">
<tr>
<td onclick="addRows(document.getElementById('tbodyA'));">
Click me to add rows
</td>
</tr>
</tbody>
</table>
</body>
</html>
 
R

RobG

Thomas said:
This sure helps me a lot! Thank you for your time and answers. But I
have a new problem now: The variable v_rowid always has the newest
value it was assigned, so the last row is always chosen. :s
Can I add parameters to the function so it always works?

I was hoping someone could explain things better, ah well.

Anyhow, the way to break the scope chain is to have the onclick added
by an external function, not an internal one. My post above provides
code to demonstrate the issue, below is a modified version that fixes
it (tested: Firefox, IE).

The trick is to pass values to another function and add the onclick
from there. My guess is that this breaks the chain back to 'i' and
so its literal value is used for the onclick, not the variable
reference.

At the bottom I have added what I think will work for your case.



/******** Demo fix *****************/

<script type="text/javascript">
function addRows(t){
var cell, row, rowId,
i = t.rows.length,
j = i + 5;
for ( ; i<j; i++ ){
row = t.insertRow(i);
row.id = 'row-' + i;
addClick(row,i);
cell = document.createElement('td');
cell.appendChild(document.createTextNode(i))
row.appendChild(cell);
}
}

function addClick(x,y){
x.onclick = function() {
alert('this.id: ' + this.id + '\nstatic value: row-' + y)};
}
</script>



/******** Your fix *****************/

function .... {
...

addOnBlur(CellPostcodeTekst,
'p_plaats_sys_vest' + v_rowid,
'p_postcode_vest' + v_rowid,
'p_gemeente_vest' + v_rowid );

...
}

// Outside the above function
function addOnBlur(PostcodeTekst, plaats_sys, postcode, gemeente){
PostcodeTekst.onblur = function (){
call_zoekgemeente_byID( plaats_sys, postcode, gemeente )
};
}

Hope that does the trick (untested of course!).
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top