Click here to Skip to main content
Click here to Skip to main content

Easy DHTML treeview

By , 21 Feb 2002
 

Sample Image - DHTML_Treeview.jpg

Introduction

Have you ever tried to insert an easy-to-use treeview into your homepage or even use a treeview in your web-application? If you have, you will probably know that most ready-made treeviews out there are built in a quite complex manner, making heavy use of client side javascript and difficult-to-handle structures like multi-dimensional arrays and such. There is, however, a more elegant way of implementing a treeview using only one small client-side javascript and making use of DOM (Document Object Model) and basic HTML-tags such as DIV.

Easy DHTML Treeview

The 'Easy DHTML Treeview' builds a treeview on top of the Document Object Model, which already is hierarchical by definition. The whole idea of the 'Easy DHTML Treeview' is using simple HTML tags such as DIV and A to create the real tree and then using one simple javascript function (triggered by clicking on a branch) to collapse and unfold all of the children (branches and leaves) by hiding or showing the DIV-item (if a DIV item is hidden, all the children of the DIV item are hidden as well).

Overview of design

So, when you click on the yellow 'branch name', the javascript function Toggle will be called with a pointer to the branch name itsself. The Toggle-function will then ask the document (using DOM) what the next item is (which in this case is the yellow DIV-section) and hide it. If the yellow DIV-section is hidden all items inside the yellow square (which is almost everything in the picture) will be hidden as well.

Serialising the treeview

The good thing about this simple implementation is that it is very easy to construct a treeview from data that can be stored in a database. Whereas other treeview functions and components force you to fill a javascript array (which is only 2 levels deep anyway and therefore not a real n-level tree), 'Easy DHTML Treeview' allows you to simply print the data as if it were a table. The whole functionality of collapsing and unfolding the branches in the tree is then added almost automatically by the single function that does it all!

The included demo-project shows you that it is really quite easy to create very dynamic, n-level truly recursive trees using 'Easy DHTML Treeview'. For storing the data in the tree, this data model is used:

E-R Diagram

Like a treeview, the data model itself is recursive, because topic and topic_1 are the very same table. This means topic has a relation to topic, with the subtopic table in between to implement an n-n relationship.

Tips & Tricks

I got a lot of questions about the treeview so I'd just answer some of them here for your convenience:

How can I change the initial state of the treeview from collapsed to expanded? The answer is quite simple. If you're using the static version (from the live demo-site, simply omit the style attribute from the DIV-tags. So what was < DIV style='display:none' > simply becomes < DIV >. And of course if you're into details, you should change the images in front of the items from plus.gif to minus.gif. If you're using the scripts that generate a tree from a database, you should hack it the other way around, because that sample is initially expanded. It's quite straightforward, but when I find the time I could post 2 versions of the samples, one collapsed and the other one expanded.

How can I liven up the treeview to make it look better? Well, I've been working on a pure-HTML extension of the treeview with a colleague of mine, which draws lines in the treeview, like MFC treeviews do. I will post this version shortly.

Cross-browser treeview?

I developed this treeview for Internet Explorer 5, which is not such a good idea if you want to develop a cross-browser treeview because Microsoft has the tendency to build all kind of fancy non-standard goodies into it's browser. Luckily some people on the CodeProject have tested it on other browsers and it only seemed to work on IE5 (not even IE4!). I'm now in the process of evaluating what I can do to improve this. Today (June 13th 2001) I checked all my script-entries against the actual standards and found out that all of it should work on browsers supporting CSS Level 1, HTML 4.0 and DOM Level 2. I made some modifications today as well and I'm curious on which browsers the script works correctly.

The treeview has been tested on the following browsers:

Microsoft Internet Explorer 4 (SP 2)Doesn't Work!
Microsoft Internet Explorer 5.0 (for Macintosh)Work partially (different look)
Microsoft Internet Explorer 5.00.3103.1000Works!
Microsoft Internet Explorer 5.50.4522.1800C0Works!
Microsoft Internet Explorer 6.00.2462.0000Works!
Netscape 4.77Doesn't work!
Netscape 6Works!
Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; 0.8.1) Gecko/20010323Works!
Opera 5.0 (Build 528 on Windows 2000)Doesn't work!
Opera 6Doesn't work!

(Thanks to Jorge Sabater Redondo, Alexandra Berg, Neal Costello, Zinggl Alois, Jens Kreiensiek, Arnt Witteveen, Jamie Nordmeyer, Bryan Pietrzak and Bruce for the testing!)

If you have another browser than listed above, please test the script at THIS live-demo site and mail me to tell me if it did or didn't work on your browser... Together we can build a better treeview, I know it! ;-)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

D.D. de Kerf
Web Developer
Netherlands Netherlands
Member
I completed college Higher Informatics (HIO Breda, The Netherlands) in august 2000. I have been software engineer/documentalist/project manager with Bodégro Technical Automation since 1998 (started as part-time, full-time since august 2000).
 
Lots of experience with Delphi, Visual C++, PL/SQL, ASP and PHP. Started a succesfull knowledge-sharing initiative in late 1999 called 'Cohort Forum', which resulted in a web-site a lot like the codeproject.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionHREFmemberMichael Janulaitis18 Jan '12 - 11:49 
When I search this discussion I see some people have added HREFs but it seems CodeProject is unable ot load their messages...like they have been removed from the discussion. Anyway, how can this be done. The tree seems to only be an informational tool otherwise.
QuestionWorks In ChromememberDaaron11 Jul '11 - 7:02 
Appears to work in Chrome 12.0.742.112
Cheers,
Daaron

GeneralIE8memberZe2103826 May '10 - 4:03 
work's fine in internet explorer 8.
thank you.
GeneralThank youmemberOmarGamil31 Oct '09 - 22:57 
Great Article
GeneralFROM ASP TO PHP AND MYSQLmemberpogramadox9 Oct '09 - 9:05 
Thanks, great code, here is in php. Just copy and paste into the two code files. The database named test was exported as sql from phpMyadmin. It's dump is down.
 
FIRST demo.php:
 
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft FrontPage 4.0">
<META HTTP-EQUIV="Content-Type" content="text/html; charset=iso-8859-1">
<TITLE>Easy DHTML TreeView dynamic sample</TITLE>
</HEAD>
<BODY>
 
<?php include("DHTML_TreeView.inc"); ?>
<HR>
<?php

// Init the treeview
InitTreeView();
 
// Get the topics from the database and draw the treeview
TopicsInTree();
?>
 
<BR><BR><HR>
<SCRIPT LANGUAGE="JavaScript">
 
//execute once page has loadded
var aTags = document.getElementsByTagName('A');
 
for(var n = 0; n < aTags.length; n++)
{
if(aTags[n].onclick.toString().indexOf('Toggle(this)') > 0)
{
Toggle(aTags[n]);
}
}
 
</SCRIPT>
 
</BODY>
</HTML>
 
AND LAST DHTML_TreeView.inc
 
<?php
function InitTreeView(){
?>
 
<SCRIPT LANGUAGE="JavaScript">
 
// ---------------------------------------------
// --- Name: Easy DHTML Treeview --
// --- Author: D.D. de Kerf --
// --- Version: 0.1 Date: 6-6-2001 --
// ---------------------------------------------
function Toggle(node)
{
// Unfold the branch if it isn't visible
if (node.nextSibling.style.display == 'none')
{
// Change the image (if there is an image)
if (node.childNodes.length > 0)
{
if (node.childNodes.item(0).nodeName == "IMG")
{
node.childNodes.item(0).src = "minus.gif";
}
}
 
node.nextSibling.style.display = 'block';
}
// Collapse the branch if it IS visible
else
{
// Change the image (if there is an image)
if (node.childNodes.length > 0)
{
if (node.childNodes.item(0).nodeName == "IMG")
{
node.childNodes.item(0).src = "plus.gif";
}
}
 
node.nextSibling.style.display = 'none';
}
 
}
</SCRIPT>
<?php
 
} ////////////////
 

// Helper function for TopicsInTree. This function will be called recursively to load the whole tree from
// the database
function SubTopicsInTree($DBconnection, $topicID, $topic, $depth){
 
// Query the database for all the direct subtopics of topic topicID
$query = "SELECT topicID, name FROM topic WHERE topicID IN (SELECT subtopicID FROM subtopic WHERE topicID = ".$topicID.") ORDER BY name ASC";
$rsSubtopics = mysql_query($query, $DBconnection);

$la="<FONT FACE='arial' SIZE='".(6-$depth)."'>";
$lc= "</FONT>";
echo "<TABLE BORDER=0><TR>";

// This value (now 10) represents the hoziontal spacing between the branches
//if ($depth > 1)
echo "<TD WIDTH=20></TD>";

 
// We have another branch. Solve the branch recursively
if(mysql_num_rows($rsSubtopics) > 0){

echo "<TD><A onClick='Toggle(this)'><IMG SRC='minus.gif'> ".$la.$topic.$lc."</A><DIV>";
while ($row = mysql_fetch_array($rsSubtopics)) {

$subtopicID = $row[0];
$subtopic = $row[1];
SubTopicsInTree($DBconnection, $subtopicID, $subtopic, ($depth + 1));

}
 
// We have a leaf. Simply print the leaf
}else{
echo "<TD><IMG SRC='leaf.gif'> ".$la.$topic.$lc."<DIV>";
}

echo "</DIV></TD></TR></TABLE>";

mysql_free_result($rsSubtopics);
}
 

// The function that loads the treeview from the database and draws it in HTML
// Connect to the database
function TopicsInTree()
{
$db_host = "localhost";
$db_user = "root";
$db_pass = "";
$db_name = "test";
 
$connection = mysql_connect($db_host, $db_user, $db_pass) or die ("Unable to connect to DB");
mysql_select_db($db_name, $connection);

 

// Query the database for topics that are no subtopic (so we'll get only the main topics)
$query = "SELECT topicID, name FROM topic WHERE topicID NOT IN (SELECT subtopicID FROM subtopic) ORDER BY name ASC";
$result = mysql_query($query, $connection);
echo "<TABLE BORDER=0>";
 

while ($row = mysql_fetch_array($result)) {
echo "<TR><TD>";
$onderwerpID = $row[0];
$onderwerp = $row[1];
 
// Every main topic is a branch of it's own, so they have to be solved
// recursively
SubTopicsInTree($connection, $onderwerpID, $onderwerp, 1);
echo "</TR></TD>";
}

echo "</TABLE>";
 
mysql_free_result($result);
mysql_close($connection);
 
}
 
?>
 
database test dump
 
-- phpMyAdmin SQL Dump
-- version 3.2.1
-- http://www.phpmyadmin.net
--
-- Servidor: localhost
-- Tiempo de generación: 27-01-1980 a las 01:56:53
-- Versión del servidor: 5.1.37
-- Versión de PHP: 5.3.0
 
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
 
--
-- Base de datos: `test`
--
CREATE DATABASE `test` DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish_ci;
USE `test`;
 
-- --------------------------------------------------------
 
--
-- Estructura de tabla para la tabla `subtopic`
--
 
CREATE TABLE IF NOT EXISTS `subtopic` (
`topicID` int(11) NOT NULL,
`subtopicID` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;
 
--
-- Volcar la base de datos para la tabla `subtopic`
--
 
INSERT INTO `subtopic` (`topicID`, `subtopicID`) VALUES
(1, 4),
(1, 5),
(1, 6),
(3, 16),
(3, 17),
(3, 18),
(3, 19),
(4, 7),
(4, 8),
(5, 9),
(6, 10),
(6, 11),
(6, 12),
(11, 13),
(11, 14),
(11, 15);
 
-- --------------------------------------------------------
 
--
-- Estructura de tabla para la tabla `topic`
--
 
CREATE TABLE IF NOT EXISTS `topic` (
`topicID` int(11) NOT NULL AUTO_INCREMENT,
`name` text COLLATE utf8_spanish_ci NOT NULL,
`description` longtext COLLATE utf8_spanish_ci NOT NULL,
PRIMARY KEY (`topicID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci AUTO_INCREMENT=20 ;
 
--
-- Volcar la base de datos para la tabla `topic`
--
 
INSERT INTO `topic` (`topicID`, `name`, `description`) VALUES
(1, 'Animals', ''),
(2, 'Humans', ''),
(3, 'Plants', ''),
(4, 'Cats', ''),
(5, 'Dogs', ''),
(6, 'Fish', ''),
(7, 'Siamese cat', ''),
(8, 'Street cat', ''),
(9, 'Dalmatian', ''),
(10, 'Goldfish', ''),
(11, 'Killer fish', ''),
(12, 'Salmon', ''),
(13, 'Shark', ''),
(14, 'Piranha', ''),
(15, 'Killer penguin', ''),
(16, 'Apple', ''),
(17, 'Pear', ''),
(18, 'Apricot', ''),
(19, 'Banana', '');
Questionadd href?memberneil.guo4 Nov '07 - 1:25 
This is a great treeview!
 
Has anyone tried to add links (href) to the branches?
 
I have successfully added HREF to the leafs, but not the branches as there seems to be conflict between href and toggle() as both respond to the onClick event.
 
Thanks,
 
Neil
GeneralPerformancememberjiggyman21 May '07 - 15:29 
Hi guys,
 
The tree is definitely a great control
 
I have tried using a similar approach to building a tree view in my web site. I'm using it to generate a tree of about 150 nodes. Unfortunately, it takes about 90 seconds (@100% processor usage) to generate the tree. I migrated the database from Access to SQL Server Express and noted an improvement in performance (around 60 - 70 seconds).I would suggest that this is because of the number of database calls that need to be made using the recursive approach.
 
At the moment, I'm starting to freak, as I don't think that my clients would be happy at waiting a minute for a page to load. I'm guessing that when I move this to a shared hosting environment, that this would slow down even further.
 
Can anyone else think of a way to populate this tree using (maybe Confused | :confused: ) a single database call?
 
Cheers.
GeneralRe: PerformancememberEntropy23 May '07 - 3:19 
It is not too difficult to request a whole tree of structure in either XML or JSON format (take a look at an example from google: http://code.google.com/webtoolkit/document/examples/jsonrpc/demo.html)
 
However note that once you get into a lot of nodes in your tree, you may still have performance problems, not from SQL query time, but instead from the time taken for your browser to parse and render a complex DOM.
GeneralOne node expanded at timememberLina_7919 Apr '07 - 4:38 
we have used this treeview in my project & it's excellent, but i need some help in modifying it. what i need for my project that the user can expand one node at a time. if he moves to another root tree node, the first one expanded will collapse & the second one will expand.
 
any help please?

 
Lina Naser
http://www.dotnet-guru.com

NewsNew VersionmemberAndrewVos9 Nov '06 - 22:18 
I have done an updated version of the dhtml treeview, which is easier to use.
 
http://www.codeproject.com/useritems/IE_FF_DHTML_TreeView.asp
 
Thanks for the idea BTW, it really helped me out!

 

 
www.wickedorange.com
GeneralRe: New VersionmemberLTSpeed12 Nov '06 - 13:56 
Great Work! Apologies for this newbie question, but how can I make Expand All/Collapse All work if the links are in a different frame than the tree itself?
 
I've learned a lot from looking over your example, but can't seem to get the technique down for multi-frame pages with js to work with it. It's likely I'm missing something simple.
General!!!!How to make code work with FireFox!!!!memberAndrewVos6 Nov '06 - 1:50 
In the Toggle function replace "children" with "childNodes", as it is on the demo site.
 
You forgot to modify the zip file to reflect these changes.
 

GeneralUsing event object with treememberatomicfroman14 Jun '06 - 10:08 
I am trying to setup a mouse following popup box.
 
The following is the code I am using.
function setDateGetterVis(newStyle) {
var mydiv;
mydiv = eval('document.all.dateGetter.style');
if (newStyle=='block')
{
//set the location at the point of mouse click.
mydiv.left=event.clientX;
mydiv.top=event.clientY;
}
mydiv.display=newStyle;
}
 
I have found that once the user scrolls the expanded page, the event.clientX coordinates stop where the old bottom of the page was.
 
Ideally, I would like the floating box to be able to track along with the grow and shrink of the treeview.
 
Any help would be EXTREMELY appreciated!
 
Thanks!
 
atomicfroman
-- coding my way to the next blue screen --
GeneralThe way of simplicity is often the best way...memberachainard16 Apr '06 - 20:47 
Good job...
 
...
GeneralGreat workmemberprettymeshedup11 Apr '06 - 6:02 
Thanks, really clever coding and lightweight as well.

QuestionTree Performance?memberkarba3010 Jan '06 - 18:51 
Hi
 
I just wanted to know the performance of the tree,
 
how much time will it take to construct the tree of 100K nodes?
 
has anyone tried this?
 
Regards
Bala
AnswerRe: Tree Performance?memberrajdeeep14 Feb '11 - 22:50 
Yes the performance is really slow. I am constructing around 270 sets on page load which is taking around 23-24 secs of time to load the page. Dont know if we can improve the performance of the Tree formation. But great post. Helped me a lot. Thanks Smile | :)
GeneralRetain the tree navigation pathsussAnonymous9 Sep '05 - 9:39 
Using the treeview, if I invoke a screen, when I navigate back to the treeview, is there a way to bring the navigation path back to where it was just before entering the screen.
 
Example: When I come back from screen show the treeview something like this.
 
root
|
|-Node
|-Node
|-Node
|_Node
|_ Screen

GeneralRe: Retain the tree navigation pathmemberCodeAddiction22 Dec '05 - 9:17 
Try using a little javascript to store the ID of the last node expanded in a cookie. Make sure the tree generates each node with the same unique ID value each time it is generated. Then, when the page loads, have a function that checks that cookie value to see if a node should be expanded. Then expand that node and all its parent nodes working up the tree to the top.
 
That won't get you the entire tree restored, but at least the last point you were looking at.
GeneralTHX so much !memberKahL18 May '05 - 6:56 
I really thank you for this article which, combined with an article about "how to store a tree in a database"[^], saved my life ... well not really my life but almost Smile | :)
It's clear, it's good and it works !!!
Thanks again for your good job Wink | ;)
GeneralMy first thought - this code is is great and is so horribly bloatedmemberZachJ16 May '05 - 16:02 
Cool | :cool:
 
I admit - I didnt read the article - I see code I go for it.
 
I also am not one of the insane noise that thinks tables are the devils work - but in this case - they might just have a point Smile | :)
 
Great code - How do I know? Cause I just modified it in about five minutes - and I never read the article, and never looked at the two functions that do whatever in the original code Smile | :) -
 
http://sportsforum.ws/tree
GeneralThe HTMLmemberRamon Tristani29 Apr '05 - 21:15 
Just a suggestion... Please clean up the HTML code on the sample and repost the files. Although the technique is really neat and great, the code is horrible at best. WTF | :WTF:
GeneralA helpful article!sussHTML&JavacriptLearner23 Mar '05 - 17:06 
Just want to express thanks for posting such a good article! The coding was clean and simple and it is sufficient for a simple tree view without having to use complex controls or components Smile | :)
 
Just a note: please put the tags on the next (fresh) line to indicate the end of the tag. Else, somehow, the Javascript will not be able to detect the end of the tag and thus next sibling of the current node!...strange as it is, it's true! D'Oh! | :doh:
GeneralRe: A helpful article!sussHTML&JavascriptLearner23 Mar '05 - 18:09 
I mean the </A> tags...
GeneralHTML treeviewmemberrachnadevraj@yahoo.co.in24 Jan '05 - 18:36 
I would like to populate a treeview with the contents of another treeview on which a selection is made. If I could get some help I'd be greatful.

 
Rachel

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 22 Feb 2002
Article Copyright 2001 by D.D. de Kerf
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid