HomeBlogProjects

Other Projects


JQTreeTable

  • Description/Demo
  • Docs/Download
  • Discuss/Debug

Take a plain html table, wrap the rows you want collapsing/expanding in a tbody with an id of treetable, map each row to it's parent row, set some options, and let jQTreeTable take it from there.

By wrapping it in a tbody, it means you can have other rows within the same table not part of the tree, and it also means that if javascript is disabled, users still get the plain table. A minimum of classes (three all told, with a maximum of two at any one time if highlighting and striping are enabled) are set on the <tr> element, so it should not get in the way of any styling that is set.

You can set which column takes the treeview effect, and you can also set which parents are collapsed initially. To do this, it must be done with an array, even if there is only one node you want collapsed.
A highlight option can be set so that rows change colour as they are hovered over. There is dynamic striping of the rows, and there is also a state variable, which sets whether to keep collapsed/expanded state.
Some of the graphics files are courtesy of Jörn Zaefferer's site, which I adapted for my purposes.
The full list of options are on the next tab.
Any feedback bug finds or feature requests can be left in the comments section. Over time, I hope to build up an FAQ section there.

To turn a plain table into a treetable,you just need to include jquery.js, jqtreetable.js and jqtreetable.css, and you then build it like this:
$("tbody_id_or_class").jqTreeTable(map, options);
The arguments are as follows:
map: An array of parents by row number. A child can only have one direct parent, so the row number of that parent is what goes into the array. If you have twenty rows, there would be twenty values. Top level nodes have a parent of 0.
options:
  • openImg: Relative url of the image to use for an expanded parent node.
  • shutImg: Relative url of the image to use for a collapsed parent node.
  • leafImg: Relative url of the image to use for a child node.
  • lastOpenImg: Relative url of the image to use for the last expanded parent node. Required if using lines. If not set this to the same as openImg.
  • lastShutImg: Relative url of the image to use for the last collapsed parent node. Required if using lines. If not set this to the same as shutImg.
  • lastLeafImg: Relative url of the image to use for the last child node. Required if using lines. If not set this to the same as leafImg.
  • vertLineImg: Relative url of the image to use for the vertical lines. If not using lines, set this to the same as blankImg.
  • blankImg: Relative url of the image to use for the filler that creates the indenting.
  • collapse: An array of parent row numbers whose children are collapsed initially. Must be an array even if you only want one parent collapsed
  • column: A zero based index of the column you want to show the treetable effect in, i.e. first column is 0.
  • striped: Boolean indicating whether you want a striped effect. Set the colour in the css with an even class selector.
  • highlight: Boolean indicating whether you want a highlighting effect when hovering over the rows. Set the colour in the css with an over class selector.
  • state: Boolean indicating whether you want the collapsed state of each parent to be set in a cookie. Set this to false if there is likely to be a change in the relationshiop between the child nodes and their parents.
And that's it, You now have an expandable/collapsable treetable. You can download a zip file here. It includes all the images in the examples on the first tab, the seperate css and js files, a php 5 wrapper class that can be used on the server, plus the php file used to generate the examples.

35 Comments

Post New Comment
Submitted by John Jacobs on Thu 11 Dec 2008 8:15
Hey man,
Nice script. Like that you can put up two or three of these on the same page. Thanks

Submitted by Ashish Gupta on Sun 21 Dec 2008 17:09
Hi can you provide more documentation/example on
a) structure of table
b) structure of corresponding array.

I not a php programmer, so hard for me to understand from PHP code

Your plugin looks great otherwise and I would like to use it.

Submitted by paulhan on Mon 22 Dec 2008 22:55
Hi Ashish,
Not sure how much more I can tell you. Could you expand on what you had in mind for the treetable - what server language you are working in?
Whatever way you generate it, you will end up with a plain html table, no PHP need be involved.
After that, you have to work out which rows will be parents, and which will be children, i.e. which ones will collapse. You might have this relationship mapped in a database - the usual way, or you might have your own way of doing it.
Basically, every parent will have at least one child, and could have more, but every child can only have one direct parent. This is what you need to store in the map array. So the first row will have a parent of 0. If the second and third row are children of the first row, their parent will be 1, and so on until you get to the last row. If you look at the examples, it should become clear as to how it's mapped.
HTH,
Paul.

Submitted by Ashish Gupta on Tue 23 Dec 2008 23:59
Not sure why I cannot make it work.

here is the url http://www.woodranchit.com/newcasetree/


Submitted by paulhan on Wed 24 Dec 2008 6:42
Hi Ashish,
Just looked at it and first thing I noticed is your images don't seem to be loading. Also, what does map1 contain? I'm getting map1 is not defined.
For the page you showed me, try map1 = [0, 1, 1, 0, 4, 5]. That should put Row 1 and Row 4 as top level parents, Row 2 and Row 3 as children of row 1, row 5 as child of row 4 and row 6 as child of row 5.
Paul

Submitted by simba on Thu 25 Dec 2008 13:10
Simple and beautiful , I had been used it in my project, Thank you , Paulhan!

screenshot: http://hiphotos.baidu.com/51plan/pic/item/7d85813f6ca74bdf7d1e713b.jpg

Submitted by Josh Holloway on Thu 01 Jan 2009 17:43
Hey,

This is amazing! I am using it as part of a CMS:
http://www.betterbrief.co.uk/jqtreetable.png

I would, however, really value something which made it a more spangly.

This: [url=http://www.guistalk.com/labo/] uses jquery effects which I would like to use, but don't have the expertise in javascript (at all!) to find where in your code to put effects.

I also had to hack around it a lot to get icons for empty folders displaying, so that's how you could expand it maybe.

Anyway, thanks for a great plugin! Help with slide-down effects (or whatever) would be appreciated!

Josh

Submitted by paulhan on Fri 02 Jan 2009 0:14
Hi Josh,
Thanks for the comments. The guistalk website uses an unordered list, as against a table which makes it easier to render the effect, and I spent most of the time coding it to be fast rather than trying to slow it down :). I'll have a look into it further soon, but there's a few other things I need to get through first

Submitted by Remco Aalbers on Fri 16 Jan 2009 15:23
Hi,

I'm trying to use this inside an existing (table based) layout and I 'm running into problems:

I created a simple HTML file with the usual

<table class=\"tablemain\">
...


in it and it works beautifully.

However, when I wrap the 'tablemain' table inside another table, like so

<table>
<tr>
<td>
<table class=\"tablemain\">
...
</table>
</td>
</tr>


then it breaks, I think because somehow the row numbers no longer match the correct rows. Clinking on the topmost collapsible item sets the collapsed CSS class to the first row of the wrapper table, effectively hiding the whole table.

I've tried to look in the .js code, but I'm fairly new to jquery and I'm not sure what the correct fix should be.

Any help would be appreciated! Just some confirmation that this indeed should be fixed and maybe some pointers as to what would be the best way to do it may be enough for me to fix it and I would be more than happy to share my changes back with you for an improved, more robust version.

Remco.

P.S. BTW the submitted date/times of all the comments seem to be broken, they are all at the current time

Submitted by paulhan on Fri 16 Jan 2009 19:43
Hi Remco,
Let me check this out and I'll get back to you. By the way, it should be wrapped in a tbody with the class/id set on the tbody.
Paul.

Submitted by Richard Priddy on Wed 21 Jan 2009 15:57
Hello,

I have implemented your tree table, but am having a problem with the 'collapse' option, I have tried setting it to true, and i have also tried adding in an actual array with the nodes I want collapsed (all of them) but for some reason only the first node in my tree actually gets collapsed.

Any thoughts?

Thanks
Richard

Submitted by paulhan on Thu 22 Jan 2009 1:01
@Remco
I've tried it out wrapped in another table and no problem. Only the rows you want collapsing/expanding should be wrapped by jqTreeTable(). Best way is a tbody, set a class or id on the tbody and call that in your code.
@Richard
Without seeing any code, my guess is that the first node is being set to collapsed, and it is collapsing the whole tree. When you expand it, are the nodes you want collapsed, collapsed? If you use it, you should only use an array. The best advice I can give is try collapsing just one node i.e. collapse: [2]. Also, while debugging make sure the state variable is not set to true and delete any cookies for the treetable.
Paul.

Submitted by Richard Priddy on Thu 29 Jan 2009 10:07
Hello,

Thank you Paul, I have worked that out and the problem was somewhere in my collapse array.

I have applied your scripts to a much larger table now and because of its size, your scripting takes a lot longer to complete, therefore it looks a little untidy, is there a way to hide the table while it loads and renders?

Many thanks

Richard

Submitted by Piotr on Thu 29 Jan 2009 15:07
Hi Paul,

Before I start testing your plugin one thing I must know...
Is it possible to add childrens on the fly? I mean is it possible to rebuild treetable from ajax calls/responses during page use?

regards,
Piotr

Submitted by paulhan on Fri 30 Jan 2009 2:33
@Richard,
Glad you sorted it out. In order to hide the table you would need to go into the jQTreeTable code, and edit it directly.
At line 67 just before

for (var x=0,xl=map.length; x<xl;x++){

you'd need to put

$(\"#\" + tid).hide();

and then before the call to stripe(); on line 87, you'd need to put

$(\"#\" + tid).show();

That should work.

@Piotr
It is possible, but each time you update the table, you would need to provide a new map array to reflect the new hierarchy, and then call jQTreetable on the new table again. It should be OK as long as the data set isn't insanely big. If it is, maybe hiding the table as above might help.

Submitted by Richard Priddy on Mon 02 Feb 2009 10:24
Hello,

Thank you for your code, talking to the development team here we have come up with a different solution as well, if you are interested:
we created a loading Div:
<div id=\"loading\" style=\"position:absolute; left:10; top:10; width:100px;\">
<marquee behavior=\"scroll\" direction=\"left\">* * *</marquee>
</div>

and added into your options another parameter for a function:
var options1 = { onFinishLoading: function() {$(\"#loading\").fadeOut(); $(\"#tableDiv\").fadeIn()}, openImg: \"...

and to utilise this we added on line 108:
if (opts.onFinishLoading) opts.onFinishLoading();

Hope this is of some use to someone else...

Richard


Submitted by Richard Priddy on Tue 03 Feb 2009 15:58
Hello,

I know I keep wanting to change things, or have things done differently, but I have just one last query.

Your code allows the table to be striped, what happens if i want all the rows in my table grey, with each child a slightly lighter grey.

For example a root row would be a dark grey, every row with just one ancestor would be a ligher grey, and each row with two ancestors would be lighter than that etc...

Any thoughts on how this would be achieved? I have been looking at your javascript and cant work out any way to find out how many ancestors a particular row has.

Thanks in advance

Richard

Submitted by paulhan on Tue 03 Feb 2009 22:47
Hi Richard,
That sounds like an elegant compromise for large tables.
With regard to your other query, the mapa array will give you what you need.
Basically, when you feed it the initial map of parents to children, this gets parsed into a two dmensional array of children to parents, so any node that is a parent will have a corresponding array (even if it has only one child) of the indexes of its children in the mapa array. So you could then use the length property on that array to find how many children a parent node has. If a node is only a child, it will not have an entry in the mapa array, so you'll need to do an if(mapa[index]) test. if you look at the for loop on line 68 - 74, you'll get an idea how it is constructed. It's tricky in the sense that the mapa array is zero based, but it stores the children as one based. The reason is that zero is reserved for the invisible root, i.e. the parent of the top level parents.

Submitted by AlexWS on Fri 13 Mar 2009 9:10
Very interesting plugin, but not work in Google Chrome... sad.

Submitted by William on Thu 19 Mar 2009 6:32
Hi there, thanks for the great plugin.

I've encountered a problem when using the plugin.
When nodes of the table are collapsed, a \"tree\" attribute is written into the session. When the same nodes are expanded again, the value of the tree attribute in the session would but set to an empty string. At this point if the browser is refreshed, the empty tree attribute in the session will cause a problem in firefox and google chrome.

Perhaps a check on the tree attribute before using it?

thanks again, the plugin really is a huge help

William

Submitted by paulhan on Mon 23 Mar 2009 14:11
Hi William,
Thanks for the comment. I'll put in a check for an empty cookie, as you suggested.
@Alex,
What problems are you encountering. I'm using it now in Google Chrome with no issues


Submitted by Dave Cahall on Tue 28 Apr 2009 2:51
I like what I see but I feel pretty stupid. I can not really see how to get started. I would like to see a better example where I can see the table and the code to actually make it work.

Yes the page looks good but I would like to see the table and what it looks like.

Submitted by paulhan on Wed 29 Apr 2009 1:00
Hi Dave,
Easiest thing to do is to download the zip file. That has examples in it, including the php file that generates the map of parents to children. If after that you have any specific questions, I'll do my best to help.
Paul

Submitted by Akshaya Kaushik on Sat 02 May 2009 11:24
hi,


Can we add new row dynamically through the JavaScript in the JQtreetable.

Regards
Akshaya

Submitted by paulhan on Sat 02 May 2009 19:15
Hi Akshaya,
Yes, it can be done, but there isn't a way to do that in jQTreeTable yet. You need a way to add it, i.e. a button or a context menu, and then you will need to do an insertBefore or after on the new row, and then rebuild the map to reflect the new hierarchy, and finally, reload the treetable.

Submitted by Akshaya Kaushik on Tue 19 May 2009 8:06
Hi Paul,

Hope you are doing fine.

Please accept my thanks for the suggestions provided by you. I just got busy in some other projects and have to move focus on them.

Paul as per suggested by you I have written a function to add new row but not getting to how to reload the complete treatable without using the post back.i have also succeeded in generating the arrays dynamically form the java script. But when i apply it to the tree table it doesn't remove the formatting but first array. this make all the efforts to zero.

I am just sending u the code what I have written. May be u show some light on this.

<span onclick=\"insertRow('treet1','txtInsertIndex','errorMessage');\">[+]</span>

function insertRow(tblId, txtIndex, txtError)
{
//alert(tblId)
//alert(txtIndex)
//alert(txtError)
var tbl = document.getElementById(tblId);
var rowIndex = txtIndex; //2//document.getElementById(txtIndex).value;
//alert(tbl)

var newRow = tbl.insertRow(rowIndex);
var newCell0 = newRow.insertCell(0);
newCell0.innerHTML = 'yahoo';

var newCell1 = newRow.insertCell(1);
newCell1.innerHTML = 'yahoo';

var newCell2 = newRow.insertCell(2);
newCell2.innerHTML = 'yahoo';

var newCell3 = newRow.insertCell(3);
newCell3.innerHTML = 'yahoo';

var newCell4 = newRow.insertCell(4);
newCell4.innerHTML = 'yahoo';
}

-----------------------------
Thanks & Regards,
Akshaya Kaushik


Submitted by Akshaya Kaushik on Tue 19 May 2009 8:07
Hi Paul,

Hope you are doing fine.

Please accept my thanks for the suggestions provided by you. I just got busy in some other projects and have to move focus on them.

Paul as per suggested by you I have written a function to add new row but not getting to how to reload the complete treatable without using the post back.i have also succeeded in generating the arrays dynamically form the java script. But when i apply it to the tree table it doesn't remove the formatting but first array. this make all the efforts to zero.

I am just sending u the code what I have written. May be u show some light on this.

<span onclick=\"insertRow('treet1','txtInsertIndex','errorMessage');\">[+]</span>

function insertRow(tblId, txtIndex, txtError)
{
//alert(tblId)
//alert(txtIndex)
//alert(txtError)
var tbl = document.getElementById(tblId);
var rowIndex = txtIndex; //2//document.getElementById(txtIndex).value;
//alert(tbl)

var newRow = tbl.insertRow(rowIndex);
var newCell0 = newRow.insertCell(0);
newCell0.innerHTML = 'yahoo';

var newCell1 = newRow.insertCell(1);
newCell1.innerHTML = 'yahoo';

var newCell2 = newRow.insertCell(2);
newCell2.innerHTML = 'yahoo';

var newCell3 = newRow.insertCell(3);
newCell3.innerHTML = 'yahoo';

var newCell4 = newRow.insertCell(4);
newCell4.innerHTML = 'yahoo';
}

-----------------------------
Thanks & Regards,
Akshaya Kaushik


Submitted by Peter Al on Thu 21 May 2009 15:50
Hi,

Two questions here:

1.
Is it possible to collapse all node by default when the table loads? The current default will have all the nodes expanded and the option set \"collapse: true\" will only collapse all child node but leaving the top parent expanded. What I need is to have all expandable nodes collapse by default on load.

2.
Is it possible to expand all and collapse all nodes by clicking on links?

Thanks in advance for your help.

Peter

Submitted by Michael Cramer on Thu 18 Jun 2009 13:38
Hi

there are two bugs in the plugin, that makes life hard

first:
cget = function(n){
var v='',c=' '+document.cookie+';',s=c.indexOf(' '+n+'=');
if (s>=0) {
s+=n.length+2;
v=(c.substring(s,c.indexOf(';',s))).split(\"|\");
}
return v||0;
}

shouldn't heresomething of an array returned? i think so because function value is assigned to collarr which is an array, so this will result in error if push() is called on a string or integer

second:
collarr = cget(tid)||opts.collapse||collarr;


collarr is set here to a boolean, also no longer an array and then array functions like pus() don't work anymore

Submitted by Michael Cramer on Thu 18 Jun 2009 13:39
Hi

there are two bugs in the plugin, that makes life hard

first:
cget = function(n){
var v='',c=' '+document.cookie+';',s=c.indexOf(' '+n+'=');
if (s>=0) {
s+=n.length+2;
v=(c.substring(s,c.indexOf(';',s))).split(\"|\");
}
return v||0;
}

shouldn't heresomething of an array returned? i think so because function value is assigned to collarr which is an array, so this will result in error if push() is called on a string or integer

second:
collarr = cget(tid)||opts.collapse||collarr;


collarr is set here to a boolean, also no longer an array and then array functions like pus() don't work anymore

Submitted by Michael Cramer on Thu 18 Jun 2009 14:08
Hi again,

i noticed another bug, maybe its an improvement.
rendering a hidden treetable with stripping enabled result in a not stripped table, because of the visible selector. also its never a bad idea to add also a odd class like the even one

$(\"#\"+tid+\" tr:visible\").filter(\":even\").addClass(\"even\").end().filter(\":odd\").removeClass(\"even\");


better is that way:
$(\"#\"+tid+\" tr:not(.collapsed)\").filter(\":even\").addClass(\"even\").removeClass(\"odd\").end().filter(\":odd\").removeClass(\"even\").addClass(\"odd\");


but the selector shouln't be use the visible selector

last one, thanks for the plugin, i will use it in phpsysinfo in the next release

i can also verify that it works quite well with jQuery 1.3

Submitted by paulhan on Fri 19 Jun 2009 2:16
Hi Michael,
Many thanks for the feedback. The first two are out and out bugs. The third I'll look into and align with best practices.
It has been my intention to overhaul that code to enable some features. This will encourage me to move it up the list.

Submitted by Michael Cramer on Fri 19 Jun 2009 7:00
hi,
have you a version where the first two bugs are fixed? i would really like to use your plugin
thanks

Submitted by Michael Cramer on Sat 27 Jun 2009 18:33
hi,

any news about a fixed version? please don't blame me, but i really would like to use your plugin, any other i found are little bit overloaded

regards

Submitted by Massimiliano on Fri 03 Jul 2009 18:01
Hi Paulhan,
this script is very nice! Only one question: how can I have a link or button to expand all or collapse all? Thank you!
Add comments here
Name:
Email:
URL:
Comment:BoldItalicUnderlineCreate linkCode BlockInsert Unordered List

JQuery/PHP Website and Applications Developer, based in Ireland.
Interests: Open Source Software, Supercomputers, Financial Markets, Sport, Science, Sustainable Energy. AGW Skeptic.

follow paulhan on twitter
Help me build a supercomputer