Solved

Netscape DOM and event handling

Posted on 2002-03-26
13
266 Views
Last Modified: 2013-11-19
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
Comment
Question by:klausen
  • 6
  • 4
  • 2
  • +1
13 Comments
 
LVL 23

Expert Comment

by:b1xml2
ID: 6896065
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
 

Author Comment

by:klausen
ID: 6896316
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
 
LVL 23

Accepted Solution

by:
b1xml2 earned 300 total points
ID: 6898022
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
 

Author Comment

by:klausen
ID: 6898698
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
 
LVL 23

Expert Comment

by:b1xml2
ID: 6898733
welcome =)
0
 
LVL 12

Expert Comment

by:ahosang
ID: 6900976
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 23

Expert Comment

by:b1xml2
ID: 6901013
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
 
LVL 12

Expert Comment

by:ahosang
ID: 6901962
Didn't say the code was bad. My last sentence shows exactly what my point is :-)
0
 
LVL 23

Expert Comment

by:b1xml2
ID: 6901995
rofl, can we line all the developers of these browsers and send them off to siberia *Grin*
0
 

Author Comment

by:klausen
ID: 6912238
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
 
LVL 23

Expert Comment

by:b1xml2
ID: 6912244
klausen, check my responses in the Browser section on Netscape, XML Transforms and XHTML. Thanx
0
 

Expert Comment

by:EasyDesigns
ID: 7374523
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
 

Author Comment

by:klausen
ID: 7377543
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

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

I found this questions asking how to do this in many different forums, so I will describe here how to implement a solution using PHP and AJAX. The logical flow for the problem should be: Write an event handler for the first drop down box to get …
Browsers only know CSS so your awesome SASS code needs to be translated into normal CSS. Here I'll try to explain what you should aim for in order to take full advantage of SASS.
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
The viewer will learn how to dynamically set the form action using jQuery.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now