tags:

views:

3271

answers:

3

I have a tree with ul and has the following structure:

<div id="Tree">
  <ul>
    <li>
      <a class="collapseLink" href="#">
        <span class="hide">Expand Root Node</span>
      </a>
      <a class="selectLink" href="#">
        Root Node
      </a>
      <ul>
        <li id="item_1">Sub Node 1</li>
        <li id="item_2">Sub Node 2</li>
        <li id="item_3">Sub Node 3</li>
        <li id="item_4">Sub Node 4</li>
        <li id="item_5">Sub Node 5</li>
        <li id="item_6">Sub Node 6</li>
      </ul>
    </li>
  </ul>
</div>

I would ideally like to limit the number of the Sub Nodes in the tree and tried to implement that with the following:

$(document).ready(function() { 
    var rootNode = $('#Tree ul li a:first');
    // If the root node has an 'expandLink' class then it's closed and can be opened    //(via a click)
    if (rootNode.hasClass('expandLink')){
       rootNode.click();
       limitRootNodes();
    }
    function limitRootNodes() {
        // Get the direct child nodes for the root list element
        var tree_ul = $('#Tree ul li ul:first').children();
        // list limit
        var max_listCount = 3;
        // remove the last element if the list size exceeds the limit
        while (tree_ul.size() > max_listCount){
            $('li:last-child', tree_ul).remove();  
        }   
    }
});

However, the above code is not removing the excess list elements. Any suggestions as to what is causing this?

+2  A: 

Your tree_ul variable is selecting all the children of that ul, then you're trying to select :last-child of the children of that li (for which no children exist). Try:

$('li:last', tree_ul).remove();

From the jQuery Documentation:

:last-child

Matches all elements that are the last child of their parent. While :last matches only a single element, this matches more then one: One for each parent.

:last

Matches the last selected element.

Another option is to use filter():

var max_listCount = 3;
$('#Tree ul li ul:first').children().filter(function(index){ 
  return (index >= max_listCount); 
}).remove();

This will remove all child nodes with index >= max_listCount.

John Rasch
Thanks John for your timely contribution. However, on changing the attribute as per advice it didn't work. I would like to believe maybe where I'm calling the method is wrong?
chridam
T B has pointed out my mistake. I've update it to include the filter() function which is probably the cleanest way to do this.
John Rasch
+1 I added your filter() solution to my code.
T B
+2  A: 

First off, as John has already pointed out, you are not going to remove anything with the selector that you are using. I removed the "children()" part of the tree_ul variable to help with that. Also, since you are storing tree_ul in a variable, tree_ul.size() will return the same value even after you remove children since it will not be updated after items are removed.

Here is the updated code that should work for you:

$(document).ready(function() { 
var rootNode = $('#Tree ul li a:first');

// If the root node has an 'expandLink' class then it's closed and can be opened    //(via a click)
if (rootNode.hasClass('expandLink')){
   rootNode.click();
   limitRootNodes();
}
function limitRootNodes() {
    // list limit
    var max_listCount = 3;
    // remove the last element if the list size exceeds the limit
    $('#Tree ul li ul:first').children().filter(function(index){ 
        return (index >= max_listCount); 
    }).remove();

}
});

Here is a link to view it in action http://jsbin.com/ovala

EDIT: I updated to include John's filter() solution.

T B
+1 - good catch
John Rasch
Absolutely fantastic! App now works, many thanks T B and same goes to you John.
chridam
+1  A: 

Here's another way to approach this. Replace your while-loop with this:

tree_ul.each(function(n,item){
   if(n > (max_listCount - 1))
     $(item).remove();
});

EDIT: Also, in your HTML example, the first anchor tag has class collapseLink, but this code is looking for the class expandLink before calling the limitRootNodes() function, so it is not going to get called.

if (rootNode.hasClass('expandLink')){
   rootNode.click();
   limitRootNodes();
}
Jose Basilio
Spot on José, after refactoring the code according to T B's, John's and your suggestions, my app is now working! Kudos for the decisive help.
chridam