• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 288
  • Last Modified:

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(strTableId);
     var tblBody = tbl.getElementsByTagName("tbody").item(0);
     var tblRows = tblBody.getElementsByTagName("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].childNodes[0].nodeValue < cells2[g_iSortColumn].childNodes[0].nodeValue
)
          return -1*g_iSortDirection;
         
     if ( cells1[g_iSortColumn].childNodes[0].nodeValue > cells2[g_iSortColumn].childNodes[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
0
klausen
Asked:
klausen
  • 6
  • 4
  • 2
  • +1
1 Solution
 
b1xml2Commented:
Amended Script
==============
<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(strTableId);
    var tblBody = tbl.getElementsByTagName("tbody").item(0);
    var tblRows = tblBody.getElementsByTagName("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] );
    }
    //for NS 6.x
    if (document.getElementById && ! document.all) {
                  var oNodeList = tblBody.getElementsByTagName("tr");
                  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("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].childNodes[0].nodeValue < cells2[g_iSortColumn].childNodes[0].nodeValue

)
         return -1*g_iSortDirection;
         
    if ( cells1[g_iSortColumn].childNodes[0].nodeValue > cells2[g_iSortColumn].childNodes[0].nodeValue

)
         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>
0
 
klausenAuthor Commented:
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 ?
0
 
b1xml2Commented:
klausen, it would appear that the cloneNode() method does not properly clone the events, in NS 6. Either this is an oversight on part the developers, (raise a Bugzilla Report with them if that is the case), or MSIE has implemented extensions to the W3C (which is more than likely).

>>
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.
<<

Unfortunately, yes =(

>>
In think that this makes, managing the DOM in netscape, less usefull than it needs to be. Can this really
be right ?
<<

Not necessarily. If you assign functions to events thru script, rather than thru HTML, you'd be alright. It would appear that you have stumbled on a great weakness of the DOM Implementation under 6.2.


0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
klausenAuthor Commented:
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...
0
 
b1xml2Commented:
welcome =)
0
 
ahosangCommented:
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.replaceChild( 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!!
0
 
b1xml2Commented:
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.
0
 
ahosangCommented:
Didn't say the code was bad. My last sentence shows exactly what my point is :-)
0
 
b1xml2Commented:
rofl, can we line all the developers of these browsers and send them off to siberia *Grin*
0
 
klausenAuthor Commented:
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...
0
 
b1xml2Commented:
klausen, check my responses in the Browser section on Netscape, XML Transforms and XHTML. Thanx
0
 
EasyDesignsCommented:
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_iSortColumn].childNodes[0].nodeValue) && isNumber(cells2[g_iSortColumn].childNodes[0].nodeValue)) {
     diff =  cells1[g_iSortColumn].childNodes[0].nodeValue - cells2[g_iSortColumn].childNodes[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.
0
 
klausenAuthor Commented:
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_iSortColumn].childNodes[0].nodeValue);
        var f2 = parseFloat(cells2[g_iSortColumn].childNodes[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.
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 6
  • 4
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now