Update: The javascript on this blog has been suppressed by the blogger's parser. Consequently, some of the functionality may not work. Inconvenience is regretted.

Tuesday, June 5, 2007

Client Side Expand/Collapse All Nodes For ASP.NET 2.0 Treeview

The asp.net treeview provides a lot of features/functions, one of which is the Expand/Collapse All functionality on the server side. The Treeview Control has got two function for doing just that: TreeView.ExpandAll(), TreeView.CollapseAll(). But going to server to accomplish such a simple functionality seemed a little odd to me. So, I wrote some javascript that does precisely the same. Checkout the below script:

Oops!! The current security settings of your browser do not allow the scripts on the page to access your clipboard.If you are using mozilla firefox, you may change security settings as follows: Type about:config in the url bar and set signed.applets.codebase_principal_support to true. For more info, check here or contact blog author.
 

function TreeviewExpandCollapseAll(treeViewId, expandAll)
{
var displayState = (expandAll == true ? "none" : "block");
var treeView = document.getElementById(treeViewId);
if(treeView)
{
var treeLinks = treeView.getElementsByTagName("a");
var nodeCount = treeLinks.length;

for(i=0;i<nodeCount;i++)
{
if(treeLinks[i].firstChild.tagName)
{
if(treeLinks[i].firstChild.tagName.toLowerCase() == "img")
{
var currentToggleLink = treeLinks[i];
var childContainer = GetParentByTagName("table", currentToggleLink).nextSibling;
if (childContainer.style.display == displayState)
{
eval(currentToggleLink.href);
}
}
}
}//for loop ends
}
}

//utility function to get the container of an element by tagname
function GetParentByTagName(parentTagName, childElementObj)
{
var parent = childElementObj.parentNode;
while(parent.tagName.toLowerCase() != parentTagName.toLowerCase())
{
parent = parent.parentNode;
}
return parent;
}


Get Formatted Version Of Above Script

The above script could be used as:


<a href="javascript:TreeviewExpandCollapseAll('<%=TreeView1.ClientID%>', true)">Expand All</a>
<a href="javascript:TreeviewExpandCollapseAll('<%=TreeView1.ClientID%>', false)">Collapse All</a>
<asp:TreeView ID="TreeView1" .....................



That's all there is to it.

Hope this is helpful.

Update (7/25/2008): The script has been updated to fix a minor bug concerning the toggle images being screwed up if ShowLines is false for the treeview. Thanks to comments from users, particularly to ryan.

pushp

20 comments:

Anonymous said...

Excellent posts! Very relevant to what I was looking for about client/side tree view scripting.

Thanks!

Pushpendra said...

Thanks. Glad to know all this was helpful.

pushp

Anonymous said...

Hi PushP!

You answered me on ASP.net for the same problem and your solution works fine! http://forums.asp.net/t/1050654.aspx

Now my treeviews are PopulateOnDemand (from SQL Express 2005 database) and they are working great.

But the scripts for expanding/collapsing the treeviews doesn't work anymore.

I just want to have an hyperlink that will populate and expand all of these treeviews with a single click without postback.

I understand that the treeviews have to be populated before they can be expanded (and that's why the scripts doesn't work anymore).

How can i fix this?

Please post your comments at http://forums.asp.net/t/1050654.aspx

Thanks in advance.

Pushpendra said...

check my reply here: http://forums.asp.net/p/1050654/1799986.aspx#1799986

Anonymous said...

HI I am using IE tree view control..
will this code works for the same...
and one more question what is "a"
in get elementbytag("a")

waiting for ur reply..

Thanks Sathish

Pushpendra said...

I'm not sure whether this code will work with 'IE tree view control'. It may work if similar markup is rendered by both Treeview control in asp.net 2.0 and the IE tree view control.

The code can be tweaked to work for IE tree view control.

The getElementsByTagName("a") gets all anchor elements(<a href=...) inside the element on which the function is called, tree table in this case.

Anonymous said...

Hi,
tanx for replying...
I tried but its not working...
Actually I did the same in code behind..but my manager asked me to try the same with java script
wll do some r&d and if i could slove i will post it here..

Anonymous said...

When I expand / collapse the expand / collapse images are missing. eg. when all nodes are collapsed, I click expand all and everything expands fine, and the first + image is present but all subsequent ones are missing. I'm using the default images.

Any ideas?

Pushpendra said...

Hi,

I retested the code and it works fine, all images are properly displayed on Expand/Collapse action. Hope you have not tweaked the script. Ensure the page is properly loaded before you perform any action.

Hope this helps.

Anonymous said...

Fantastic Code. I want one more thing. When on clicking on parent node all child nodes getting checked, i want that all these child nodes should expand also alongwith that.

Anonymous said...

Hi PushP,

Thank you SO much for creating this wonderful piece. You have helped many people like me. I just wanted to say "THANKS". I really appreciate this.

Thanks again!

Anonymous said...

Thank you for taking the time to come up with a client side solution, however, I am having the same issue as above... images are messed up and/or changed to text "Expand" or "Collapse" link instead of the image. Tested in IE 7 and FF 3, ASP.NET 2.0 and the code has not been modified. It is a complete copy and paste from your site.

I have tried changing the xhtmlConformance setting in the web.config as well, which can cause the generated html in controls to be rendered differently... but I had the same outcome either way.

Pushpendra said...

Hi Ryan,

Fixed the bug and updated the script. Try it and please let me know how it fares.

Thanks for catching the bug.

pushp

Anonymous said...

Pushp -

Very cool :) It works beautifully now... I tested it in IE 7 and FF 3 again and have 0 issues/errors.

Thank you for fixing the script!

Good work sir.

Anonymous said...

Pushp,
Your blogs on Treeview control has helped me alot, it has everything what I was looking for. There is this one thing I am not clear about and I didn't

find any information about what I am going to ask.

I used the JS for check/uncheck child when a parent node is checked/unchecked.
My question is if a parent node is collapsed, is it not possible to read the check/uncheck status of the child nodes?
By default the ExpandDepth attribute of the Tree control is -1, which I guess expands to all the levels.

I am working on a four level hierarchy sturcture and I wanted to set the ExpandDepth = 0 so that the nodes are collapsed to the top level and expands only when a user expands it.

For my application I have to pass the values of the checked nodes to a StoredProc to take some action on those nodes but what's happening is if the nodes are collapsed to the top level, the node crawler (I don't know what it's called that reads checks the node status) does not grab the checked items in the collapsed nodes.

Is there a way to read to find a node is checked/unchecked even if they are in the collapsed mode?

I have been looking for a solution to this for sometime now but couldn't manage to find any helpful information and finally I decided to ask the expert :-)

Thanks again for your help.

Pushpendra said...

Hi Sara,

"My question is if a parent node is collapsed, is it not possible to read the check/uncheck status of the child nodes?"

Its very much possible to read the cheked status of child nodes of a node. I guess you need to do this in the server side code. If so, just get the parent node and check for the checked status for its child nodes:

Treenode parent = ..
TreeNodeCollection childnodes = parent.ChildNodes;

and loop thru the above collection to check the checked state.

Now, all this would work fine if you are not using the PopulateOnDemand feature of the treeview, in which case the childs are not created unless a node is expanded.

You can mail me the source at pushpendra@rocketmail.com in case you need help with this.

HTH
pushp

Anonymous said...

Sorry to respond back late to your quick reply.
Yes, I am using PopulateOnDemand in my code which I did not notice until you mentioned. To be honest I am not sure why I chose that attribute and that too assign the value True. I will try to get rid of it and see if that helps. Thanks so much again.

Regards,
Sara

Xavi said...

hi, great stuff u have here. however, when i call the javascript from my img

and change the following:
treeView.getElementsByTagName("a")

to

treeView.getElementsByTagName("img")

it it not working. any idea why?

Pushpendra said...

Hi Xavi,

I'm not sure what your requirement is but it the 'a' there that gets you an array of actual node links, each of which contains inside it the expand/collapse image and the node.

Hope this clarifies.

pushp

Anonymous said...

Hey AWESOME DUDE, I only had to tweak the code a bit to suit my treeview, and thought I'd post this incase someone ran into the same trouble...

Because my treeview PopulateNodesFromClient, occasionally the nodes that posted back to retrieve child nodes produced none because no results were available.. anyway this caused the code to look for the child nodes when there was none therefore caused an error.

In addition, in my case I have no SINGLE ROOT node, but multiple, and the code didn't quite know how to handle that so I adjusted your code adding two simple lines to fix both of these problems, hope it helps someone else

'For the first issue
for (i = 0; i < nodeCount; i++) {

/// I ADDED THIS LINE BETWEEN
if (treeLinks[i].firstChild == null) {
continue;
}
///
if (treeLinks[i].firstChild.tagName) {

' For the second issue
var childContainer = GetParentByTagName("table", currentToggleLink).nextSibling;

/// I ADDED THIS LINE AFTER
if (childContainer == null) {
continue;
}