klausen
asked on
Netscape DOM and event handling
I tried this quoestion in the browsers section, but had no luck there, so I try here with the javascript gurus instead :)
I have a problem with events in netscape (NN6.2), when adding and removing nodes in the DOM on a page.
I have made a little sample, that illustrates my problem.
I'm trying to sort the contents of a table in a webpage using the DOM to swap the TR-node.
The sort is working fine, but after having sorted the table, i loose all the eventhandlers that are
associated with the elements/nodes and their children.
In my sample the doSelect() is not called after the sort, but it works fine before the sort.
The sample works fine in IE...
I do not want other solutions on how to sort the contents of the table, as I can find that myself.
The real question is : How do I get NN62 to handle the events after changing the DOM ?
sample start
<!--
<html>
<head>
<title>..::Table Sort::..</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript">
// global vars
var g_iSortColumn;
var g_iLastSortColumn =-1;
var g_iSortDirection = 1;
////////////////////////// ////////// ////////// ////////// ////////// ///////
// function sortTable()
//
// function to sort a tab?e in a HTML page
// Sorts the table rows in the table with id as specified in
// strTableId by the column 'iCol'.
// The placement of rows, that does not have at least 'iCol' columns,
// is not specified.
//
// Only 'TR' rows that are inside the first 'TBODY' tag will be sorted.
// Only 'TD' cells are compared, so 'TH' cells first in a table are
// not moved during sort.
//
// HTML for table must be well-formed.
//
// Think twice when using ROWSPAN & COLSPAN, as iCol is used to index
// columns on each row.
//
// PARAMETERS
// iCol : Column index to sort table by.
// strTableId : Id of table to sort.
// iHeaders : Number of header lines to ignore from sort.
function sortTable(iCol, strTableId, iHeaders) {
var tbl = document.getElementById(st rTableId);
var tblBody = tbl.getElementsByTagName(" tbody").it em(0);
var tblRows = tblBody.getElementsByTagNa me("tr");
var arr = new Array( tblRows.length-iHeaders );
// create array of rows so we can sort
for ( i=iHeaders; i<tblRows.length; i++) {
arr[i-iHeaders] = tblRows[i].cloneNode(true) ;
}
// set column that sort is based on
g_iSortColumn = iCol;
// find the sort direction
if (g_iLastSortColumn==iCol)
g_iSortDirection *= -1;
else
g_iSortDirection = 1;
g_iLastSortColumn=iCol;
// peform the sort
arr.sort(sortCompare);
// write sorted data from array to table
for ( i=iHeaders; i < tblRows.length; i++) {
tblBody.replaceChild( arr[i-iHeaders].cloneNode( true), tblRows[i] );
}
}
////////////////////////// ////////// ////////// ////////// ////////// ///////
// function sortCompare
// internal function used by sortTable function
function sortCompare( val1, val2 ) {
var cells1= val1.getElementsByTagName( "td");
var cells2= val2.getElementsByTagName( "td");
if ( !cells1 || !cells2 ||
g_iSortColumn < 0 ||
cells1.length <= g_iSortColumn ||
cells2.length <= g_iSortColumn )
{
return 0;
}
if ( cells1[g_iSortColumn].chil dNodes[0]. nodeValue < cells2[g_iSortColumn].chil dNodes[0]. nodeValue
)
return -1*g_iSortDirection;
if ( cells1[g_iSortColumn].chil dNodes[0]. nodeValue > cells2[g_iSortColumn].chil dNodes[0]. nodeValue
)
return g_iSortDirection;
return 0;
}
</script>
<script type="text/javascript">
function doselect(obj) {
alert("selection:"+obj.id) ;
}
</script>
</style>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h3>Demonstration of tablesort</h3>
<table border="1" id="theTable">
<tr>
<th>
<input type="button" name="btnSort1" value="Sort" onClick="sortTable(0, 'theTable', 1)">
</th>
<th>
<input type="button" name="btnSort2" value="Sort" onClick="sortTable(1, 'theTable', 1)">
</th>
</tr>
<tr id="tr1" onclick="doselect(this)">
<td>a</td>
<td>13</td>
</tr>
<tr id="tr2" onclick="doselect(this)">
<td>b</td>
<td>12</td>
</tr>
<tr id="tr3" onclick="doselect(this)">
<td>ca</td>
<td>11</td>
</tr>
</table>
</body>
</html>
-->
sample end
I have a problem with events in netscape (NN6.2), when adding and removing nodes in the DOM on a page.
I have made a little sample, that illustrates my problem.
I'm trying to sort the contents of a table in a webpage using the DOM to swap the TR-node.
The sort is working fine, but after having sorted the table, i loose all the eventhandlers that are
associated with the elements/nodes and their children.
In my sample the doSelect() is not called after the sort, but it works fine before the sort.
The sample works fine in IE...
I do not want other solutions on how to sort the contents of the table, as I can find that myself.
The real question is : How do I get NN62 to handle the events after changing the DOM ?
sample start
<!--
<html>
<head>
<title>..::Table Sort::..</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript">
// global vars
var g_iSortColumn;
var g_iLastSortColumn =-1;
var g_iSortDirection = 1;
//////////////////////////
// function sortTable()
//
// function to sort a tab?e in a HTML page
// Sorts the table rows in the table with id as specified in
// strTableId by the column 'iCol'.
// The placement of rows, that does not have at least 'iCol' columns,
// is not specified.
//
// Only 'TR' rows that are inside the first 'TBODY' tag will be sorted.
// Only 'TD' cells are compared, so 'TH' cells first in a table are
// not moved during sort.
//
// HTML for table must be well-formed.
//
// Think twice when using ROWSPAN & COLSPAN, as iCol is used to index
// columns on each row.
//
// PARAMETERS
// iCol : Column index to sort table by.
// strTableId : Id of table to sort.
// iHeaders : Number of header lines to ignore from sort.
function sortTable(iCol, strTableId, iHeaders) {
var tbl = document.getElementById(st
var tblBody = tbl.getElementsByTagName("
var tblRows = tblBody.getElementsByTagNa
var arr = new Array( tblRows.length-iHeaders );
// create array of rows so we can sort
for ( i=iHeaders; i<tblRows.length; i++) {
arr[i-iHeaders] = tblRows[i].cloneNode(true)
}
// set column that sort is based on
g_iSortColumn = iCol;
// find the sort direction
if (g_iLastSortColumn==iCol)
g_iSortDirection *= -1;
else
g_iSortDirection = 1;
g_iLastSortColumn=iCol;
// peform the sort
arr.sort(sortCompare);
// write sorted data from array to table
for ( i=iHeaders; i < tblRows.length; i++) {
tblBody.replaceChild( arr[i-iHeaders].cloneNode(
}
}
//////////////////////////
// function sortCompare
// internal function used by sortTable function
function sortCompare( val1, val2 ) {
var cells1= val1.getElementsByTagName(
var cells2= val2.getElementsByTagName(
if ( !cells1 || !cells2 ||
g_iSortColumn < 0 ||
cells1.length <= g_iSortColumn ||
cells2.length <= g_iSortColumn )
{
return 0;
}
if ( cells1[g_iSortColumn].chil
)
return -1*g_iSortDirection;
if ( cells1[g_iSortColumn].chil
)
return g_iSortDirection;
return 0;
}
</script>
<script type="text/javascript">
function doselect(obj) {
alert("selection:"+obj.id)
}
</script>
</style>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h3>Demonstration of tablesort</h3>
<table border="1" id="theTable">
<tr>
<th>
<input type="button" name="btnSort1" value="Sort" onClick="sortTable(0, 'theTable', 1)">
</th>
<th>
<input type="button" name="btnSort2" value="Sort" onClick="sortTable(1, 'theTable', 1)">
</th>
</tr>
<tr id="tr1" onclick="doselect(this)">
<td>a</td>
<td>13</td>
</tr>
<tr id="tr2" onclick="doselect(this)">
<td>b</td>
<td>12</td>
</tr>
<tr id="tr3" onclick="doselect(this)">
<td>ca</td>
<td>11</td>
</tr>
</table>
</body>
</html>
-->
sample end
ASKER
hehe - yes this works fine ! (thanks b1xml2)
But does that mean, that I have to check all childs of my <TR> nodes (recursive) to check for other event too, if I want my sortTable() to work on other tables as well.
f.ex. is there any 'onmouseover' or 'onclick' eventhandlers on any of the <TD> elements or maybe events for another element inside one of the <TD> elements. If there is, then I need to check all childs for all possible eventhandlers which is a shame when moving elements in the DOM (changing the page) is so easy.
In think that this makes, managing the DOM in netscape, less usefull than it needs to be. Can this really be right ?
But does that mean, that I have to check all childs of my <TR> nodes (recursive) to check for other event too, if I want my sortTable() to work on other tables as well.
f.ex. is there any 'onmouseover' or 'onclick' eventhandlers on any of the <TD> elements or maybe events for another element inside one of the <TD> elements. If there is, then I need to check all childs for all possible eventhandlers which is a shame when moving elements in the DOM (changing the page) is so easy.
In think that this makes, managing the DOM in netscape, less usefull than it needs to be. Can this really be right ?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
well - it seems like there is a problem with the DOM :(
It seems that transforming XML to HMTL using XSLT also means the event are not generated - but i will ask about this in another question.
Thanks for your answer and time on this question.
Even though i'm not happy about the result - you shall have the point that i promised for an answer.
thanks...
It seems that transforming XML to HMTL using XSLT also means the event are not generated - but i will ask about this in another question.
Thanks for your answer and time on this question.
Even though i'm not happy about the result - you shall have the point that i promised for an answer.
thanks...
welcome =)
Or just don't use cloneNode() function when building array arr. Try:
arr[i-iHeaders] = tblRows[i];
and:
for ( i=iHeaders; i < tblRows.length; i++) {
tblBody.replaceCh ild( arr[i-iHeaders], tblRows[i] );
}
I used a similar sortable table once, but with innerHTML instead of replaceChild and it worked in NS6, but not in IE!
The trials and tribulations of catering to these browsers!!
arr[i-iHeaders] = tblRows[i];
and:
for ( i=iHeaders; i < tblRows.length; i++) {
tblBody.replaceCh
}
I used a similar sortable table once, but with innerHTML instead of replaceChild and it worked in NS6, but not in IE!
The trials and tribulations of catering to these browsers!!
ahosang, the problem is not with the cloneNode() method, the problem is with the propagation of the events which do not work with NS 6.x
There's nothing wrong with klausen's code. It is rather elegant.
There's nothing wrong with klausen's code. It is rather elegant.
Didn't say the code was bad. My last sentence shows exactly what my point is :-)
rofl, can we line all the developers of these browsers and send them off to siberia *Grin*
ASKER
Thought that I had already accepted your answer - but I must have forgot to press some button :)
Again - Thanks for answering, nice to have 'all-knowing' allies on this site...
Again - Thanks for answering, nice to have 'all-knowing' allies on this site...
klausen, check my responses in the Browser section on Netscape, XML Transforms and XHTML. Thanx
This script works great, but I have one complaint and that is that it does not address sorting of numeric values as appropriate (i.e. 200 comes before 50 because 2 is less than 5). Consider adding
if (isNumber(cells1[g_iSortCo lumn].chil dNodes[0]. nodeValue) && isNumber(cells2[g_iSortCol umn].child Nodes[0].n odeValue)) {
diff = cells1[g_iSortColumn].chil dNodes[0]. nodeValue - cells2[g_iSortColumn].chil dNodes[0]. nodeValue;
if (diff > 0) return g_iSortDirection;
if (diff < 0) return -1*g_iSortDirection;
return 0;
}
at the beginning of the sortCompare() function to add in sort functionality for numeric values.
isNumber() is a simple evaluation of whether or not the value passed to it is a number of any sort. email me if you need/want the script.
if (isNumber(cells1[g_iSortCo
diff = cells1[g_iSortColumn].chil
if (diff > 0) return g_iSortDirection;
if (diff < 0) return -1*g_iSortDirection;
return 0;
}
at the beginning of the sortCompare() function to add in sort functionality for numeric values.
isNumber() is a simple evaluation of whether or not the value passed to it is a number of any sort. email me if you need/want the script.
ASKER
Sounds great that you can use this. I have already created different kinds of sort functions (which is why if made it easy to change the sort function).
I have sortCompare(), sortCompareLocale(), sortCompareNumericLocale() fumctions to use with this script.
instead of isNumeric() is just use parseFloat() so that any text that begins with numbers, are sorted based on the numrric value as you suggest.
I did it like this
try {
var f1 = parseFloat(cells1[g_iSortC olumn].chi ldNodes[0] .nodeValue );
var f2 = parseFloat(cells2[g_iSortC olumn].chi ldNodes[0] .nodeValue );
if ( !isNaN(f1) && !isNaN(f2) ) {
var result = (f1 - f2)*g_iSortDirection;
if ( result != 0 )
return result;
}
} catch ( E ) { }
I have also solved my original problem, by avoiding the use of cloneNode() which is causing the problem with the lost event handlers.
I have sortCompare(), sortCompareLocale(), sortCompareNumericLocale()
instead of isNumeric() is just use parseFloat() so that any text that begins with numbers, are sorted based on the numrric value as you suggest.
I did it like this
try {
var f1 = parseFloat(cells1[g_iSortC
var f2 = parseFloat(cells2[g_iSortC
if ( !isNaN(f1) && !isNaN(f2) ) {
var result = (f1 - f2)*g_iSortDirection;
if ( result != 0 )
return result;
}
} catch ( E ) { }
I have also solved my original problem, by avoiding the use of cloneNode() which is causing the problem with the lost event handlers.
==============
<html>
<head>
<title>..::Table Sort::..</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script type="text/javascript">
// global vars
var g_iSortColumn;
var g_iLastSortColumn =-1;
var g_iSortDirection = 1;
//////////////////////////
// function sortTable()
//
// function to sort a tab?e in a HTML page
// Sorts the table rows in the table with id as specified in
// strTableId by the column 'iCol'.
// The placement of rows, that does not have at least 'iCol' columns,
// is not specified.
//
// Only 'TR' rows that are inside the first 'TBODY' tag will be sorted.
// Only 'TD' cells are compared, so 'TH' cells first in a table are
// not moved during sort.
//
// HTML for table must be well-formed.
//
// Think twice when using ROWSPAN & COLSPAN, as iCol is used to index
// columns on each row.
//
// PARAMETERS
// iCol : Column index to sort table by.
// strTableId : Id of table to sort.
// iHeaders : Number of header lines to ignore from sort.
function sortTable(iCol, strTableId, iHeaders) {
var tbl = document.getElementById(st
var tblBody = tbl.getElementsByTagName("
var tblRows = tblBody.getElementsByTagNa
var arr = new Array( tblRows.length-iHeaders );
// create array of rows so we can sort
for ( i=iHeaders; i<tblRows.length; i++) {
arr[i-iHeaders] = tblRows[i].cloneNode(true)
}
// set column that sort is based on
g_iSortColumn = iCol;
// find the sort direction
if (g_iLastSortColumn==iCol)
g_iSortDirection *= -1;
else
g_iSortDirection = 1;
g_iLastSortColumn=iCol;
// peform the sort
arr.sort(sortCompare);
// write sorted data from array to table
for ( i=iHeaders; i < tblRows.length; i++) {
tblBody.replaceChild( arr[i-iHeaders].cloneNode(
}
//for NS 6.x
if (document.getElementById && ! document.all) {
var oNodeList = tblBody.getElementsByTagNa
var szId;
for (var i=0;i<oNodeList.length;i++
szId = oNodeList.item(i).id;
if (szId.indexOf("tr") != -1) oNodeList.item(i).onclick = doselect;
}
}
}
//////////////////////////
// function sortCompare
// internal function used by sortTable function
function sortCompare( val1, val2 ) {
var cells1= val1.getElementsByTagName(
var cells2= val2.getElementsByTagName(
if ( !cells1 || !cells2 ||
g_iSortColumn < 0 ||
cells1.length <= g_iSortColumn ||
cells2.length <= g_iSortColumn )
{
return 0;
}
if ( cells1[g_iSortColumn].chil
)
return -1*g_iSortDirection;
if ( cells1[g_iSortColumn].chil
)
return g_iSortDirection;
return 0;
}
</script>
<script type="text/javascript">
function doselect(obj) {
if ("string" == typeof(this.tagName) && this.tagName == "TR") obj = this;
alert("selection:"+obj.id)
}
</script>
</style>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h3>Demonstration of tablesort</h3>
<table border="1" id="theTable">
<tr>
<th>
<input type="button" name="btnSort1" value="Sort" onClick="sortTable(0, 'theTable', 1)">
</th>
<th>
<input type="button" name="btnSort2" value="Sort" onClick="sortTable(1, 'theTable', 1)">
</th>
</tr>
<tr id="tr1" onclick="doselect(this)">
<td>a</td>
<td>13</td>
</tr>
<tr id="tr2" onclick="doselect(this)">
<td>b</td>
<td>12</td>
</tr>
<tr id="tr3" onclick="doselect(this)">
<td>ca</td>
<td>11</td>
</tr>
</table>
</body>
</html>
Notes
=====
1. You may be surprised by the results shown in NS <GRIN>