views:

155

answers:

1

I'm building a very simplistic unordered list tree in XHTML with multiple levels deep. The way it works is that you click a parent node, and it uses the jQuery .load() API to make an AJAX call back to the server to see if this node has children. If it does, it inserts those nodes inside. When you click the parent link again, it does a .remove() to remove the children.

Everything works fine in Safari, Chrome, and FireFox. But in IE6, IE7, IE8, and Opera, it's breaking.

In the IE's, the code works when expanding parents to show children. But when I click the parents to hide the children again with the .remove(), it's going into the children and doing a remove of their children, rather than itself.

In Opera, the code expands but then moves the margins over as it is expanded. Then, on remove, it exhibits the same problem as the IEs.

What could be causing this strangeness?

Sample posted here: http://volomike.com/downloads/sample1.tar.gz

+1  A: 

OK, Volomike! I looked at your code an there were a few problems:

First, when you use load, it doesn't replace the selected node, it replaces its contents.

So, you are calling load on a li but also returning the same li in your AJAX result. Subsequently, you are getting this:

<li id="node-7">
   <li id="node-7">
      ...

Also, you were closing it with two </ul> tags in your ajax.php line 38 instead of one ul and one li.

So, if you fix those things it should start working. That said, I would approach what you are doing totally differently. I hope this helps you out:

HTML

<ul id="tree">
  <li id="node-1"><a href="#">Cat 1</a></li>
  <li id="node-7"><a href="#">Cat 7</a></li>
</ul>

PHP

// You'll have to write the code, but get it into this format:
// Basically push each row of a `mysql_fetch_array` into a new array
$ret = array(
  array('2', 'Cat 2'),
  array('3', 'Cat 3')
);

// Then return it to the browser like this:
echo json_encode( $ret );

JS/jQuery

$(function(){
   $("ul#tree li a").live('click', function(e){
      e.preventDefault();
      var $li = $(this).closest('li');
      if( $li.find('ul').length ){
          // Remove UL if it exists
          $li.find('ul').remove();
      } else {
          // Get the ID
          var id = $li[0].id.replace('node-','');
          // Get the JSON for that id
          $.getJSON('/ajax.php', { id: id }, function( data ){
              // If data is not empty and it is an array
              if(data && $.isArray( data )){
                 // Build our UL
                 var $ul = $("<ul></ul>");
                 // Loop through our data
                 $.each(data, function(){
                    // Build an LI, use `text()` to properly escape text
                    // then append to the UL
                    $('<li id="node-' + this[0] + '"><a href="#"></a></li>')
                        .find('a').text(this[1])
                        .end().appendTo($ul);
                 });
                 // Finally, add the UL to our LI
                 $ul.appendTo($li);
              }
          });
      }
   });
});
Doug Neiner
You were right on the extra LI node and the multiple UL endings. Didn't realize those and should have done better debugging with firebug.
Volomike
I also found that IE and Opera are strange and return uppercase UL from $('#node-' + nClickID).html(), so must use .toLowerCase(). Also, don't check for <ul> because in some cases IE inserts extra params. Check for "<ul" in Javascript.
Volomike
@Volomike Right, ah, good catches!
Doug Neiner