Introduction
I had a need to implement several different types of tree controls in ASP lately. I looked around, did not find exactly what I wanted. There was no short supply of tree type controls for DHTML - my problem was that most were really complex and tended to do way more than what I required. The other problem (that I had) was that some of the more simple ones took a lot of code on the ASP side for even a semi-simple looking tree.
I decided that I wanted a tree that could be built with a single server-side include, no components, and was reasonably fast. So here is my first version of a tree control usable in ASP.
I will state that originally I was working with an example I found somewhere (I honestly cannot remember where), all that is left from that example are some of the images for displaying the tree, and a couple of div
names.
Background
All tree controls used in DHTML rely on JavaScript manipulating elements on the page. So (for example) if you have a DIV
element and you give it an ID like:
<DIV id=myDIV style="DISPLAY: none"></DIV>
you can then manipulate the HTML element in client-side JavaScript like this:
<script language="javascript">
var oMyDiv = document.getElementById("myDIV");
oMyDiv.style.display= "none";
</script>
That was a really simple example - but it demonstrates exactly how trees and other DHTML widgets work. You can manipulate all the attributes and so forth on an element all in script.
In my tree control I use DIV
's to encapsulate the different parts of the tree (each branch), then when you click to expand a branch, I change the DIV
's style depending on whether I want to expand (show the child DIV
), or collapse (hide the child DIV
). You can look at the source to see how all the elements are manipulated to create the tree control - it really is all based on hiding/showing and changing a few attributes.
The real crux of spitting a tree control out from ASP (in my opinion) happens in the tree construction (ASP side of things). This part was where some of the ASP examples out there really were confusing. I had a hard time believing that 3 pages of code were necessary to render a tree. I am not saying my solution is the best - but it is rather short on the code needed to do it (which I am proud of).
There are a couple of assumptions about a tree that can be made without even knowing what is going to go into it.
- All trees have branches and leaves
- A tree (when drawn) is drawn one line at a time
Number 1 makes creating a little tree API pretty simple - you are either adding leaves or starting a new branch.
Number 2 is where we can do some optimizations in the code and take out most of the logic that would normally be needed to draw a tree. Instead of using a tree-structure to draw a tree, I only track what depth branch you are on (this will become clear in a minute).
A couple of other details are that I wanted to be able to add keys to each branch and item, I wanted to be able to select, multi-select and deselect. I also wanted to prevent having to code a whole bunch of JavaScript arrays to track items.
The solution for selection/de-selection/keys is to use a hidden SPAN
element which will contain each items key (any value you want to give it), and its selection state. You are probably wondering where I am storing the selection state. I am taking advantage of the fact that these SPAN
s containing the item keys will never be visible - so I can stuff variables into the element's style
attributes with no effect on the actual page display. I put a 0 or 1 into the zIndex
attribute to tell the script whether the item is selected or not (thanks CSS!).
Last but not least, I added a custom JavaScript handler for dealing with item selections. The JavaScript prototype looks like this (we will see how to use it in a minute):
myCustomFunction(bReslect,bSelected,sKey);
bReselect
is whether or not the item was just re-selected
bSelected
whether or not the item was selected
sKey
the items key (you assign this)
Using the code
Let's get down to business and see how all this information fits together into something (hopefully) useful.
To even be able to create a tree using the scripts, you will need to include it between the <HEAD>
tags of your ASP page.
<!---->
Right after this line would be a good place to put your custom JavaScript function:
myTreeItemDispatch(bReslect,bSelected,sKey)
{
if(bSelected || bReslect)
{
alert("You clicked - " + sKey);
}
}
TreeItemDispatch = myTreeItemDispatch;
We are almost ready to spit out a tree. One thing that I added to my tree implementation was the ability to customize the icons of each node. For this to work efficiently, you register them using a number - before you start your tree. Here is an example (in ASP)
tree_RegisterBranchType 0,"images/tree/foldericon.gif"
tree_RegisterLeafType 0,"images/tree/htmlicon.gif"
I set up the potential for 10 different types of each (probably overkill). If you want to add more - just change the numbers.
We are now ready to start our tree, the tree-top in my implementation is static (i.e.: it can not be collapsed). I did this because every tree I have to make only needs the top as a description of what's in the tree. So to kick off a tree we would have some ASP that looks like this:
tree_Start "Personal Folders","images/tree/openfoldericon.gif"
This tells the tree API to start building a tree with a top item named "Personal folders" and using the specified icon.
Now we are free to add branches and leaves to our tree - the only thing we really need to keep track of is, if we are adding the last item in a branch or the tree itself - another note is that I have defined a constant (for ASP use) called tTRUE
and tFALSE
, so when adding branches and leaves we use the constant for yes/no values. To add a branch we use the tree_StartBranch
function. It takes several parameters - here is an example:
tree_StartBranch 0,tFALSE,"Test Folder","tst"
The first parameter is the branch type (which we registered above), the second parameter tells the tree if this is the last branch in the current branch (or tree), third is the caption, and the last parameter is a key you can assign to implement custom behavior on the client side.
Once we start a branch we can add leaves to it like this:
tree_AddLeaf 0,tFALSE, "Child 1","tst1"
The parameters are the same as those for tree_StartBranch
with the exception that the first parameter is a leaf type (which we registered above).
Once you have added leaves to your branch you have to end it using the tree_EndBranch
function.
Once you have added all the branches to a tree you call the tree_End
function which writes the tree out.
The usage of the API lets you easily build up a tree using only a few functions. Look in the included example and you will see it is pretty straightforward.
Closing
What happens once someone clicks on an item, is for you to implement. I wanted this to be a good little framework for tree generation - I hope you find it useful.
If you use it in something interesting - let me know.