<s:event b:on="construct" b:action="show" /> <s:include b:url="g-treelist.xml" /> <h1>Grauw’s treelist</h1> <p>Hi, this is my treelist widget for Backbase:</p> <g:treelist> <thead> <tr> <th>Subject</th> <th>From</th> <th>Posted</th> </tr> </thead> <tbody> <g:treelisttr id="tl-1"> <g:treelisttd>really long subject thingy rea (1)</g:treelisttd> <td>Marijan Milicevic - Backbase</td> <td>15-07-2005, 13:01</td> </g:treelisttr> <g:treelisttr id="tl-2"> <g:treelisttd>b:receive (2)</g:treelisttd> <td>John Doe</td> <td>23-06-2005, 17:14</td> </g:treelisttr> <g:treelisttr id="tl-2-1" b:observe="id('tl-2')"> <g:treelisttd>Re: b:receive</g:treelisttd> <td>Marcel Diepsg:treelisttra - Backbase</td> <td>24-06-2005, 8:01</td> </g:treelisttr> <g:treelisttr id="tl-3"> <g:treelisttd>include file with table sg:treelisttruct (6)</g:treelisttd> <td>John Doe</td> <td>21-06-2005, 16:07</td> </g:treelisttr> <g:treelisttr id="tl-3-1" b:observe="id('tl-3')"> <g:treelisttd>Re: include file with table st</g:treelisttd> <td>Joe Average</td> <td>22-06-2005, 13:27</td> </g:treelisttr> <g:treelisttr id="tl-3-1-1" b:observe="id('tl-3-1')"> <g:treelisttd>Re: include file with table st</g:treelisttd> <td>Otto Normalverbraucher</td> <td>22-06-2005, 14:47</td> </g:treelisttr> <g:treelisttr id="tl-3-1-1-1" b:observe="id('tl-3-1-1')"> <g:treelisttd>Re: include file with table st</g:treelisttd> <td>Jan Modaal</td> <td>23-06-2005, 6:01</td> </g:treelisttr> <g:treelisttr id="tl-3-1-1-1-1" b:observe="id('tl-3-1-1-1')"> <g:treelisttd>Re: include file with table st</g:treelisttd> <td>Otto Normalverbraucher</td> <td>23-06-2005, 6:38</td> </g:treelisttr> <g:treelisttr id="tl-3-1-2" b:observe="id('tl-3-1')"> <g:treelisttd>Re: include file with table st</g:treelisttd> <td>John Doe</td> <td>23-06-2005, 9:43</td> </g:treelisttr> </tbody> </g:treelist> <p>You can <a href="http://www.grauw.nl/articles/demos/g-treelist/g-treelist.zip">download the treelist here</a>. My website can be found at this address: <a href="http://www.grauw.nl/">http://www.grauw.nl/</a>.</p> <h2>Structure of the treelist widget</h2> <p>The treelist kind of looks like a regular table, but with some of the elements replaced by custom tags. Instead of a <code>table</code> element, there is a <code>g:treelist</code>, instead of a <code>tr</code> element (inside the <code>tbody</code>) there is a <code>g:treelisttr</code> element, and instead of a <code>td</code> element, there is <code>g:treelisttd</code>. Now, if you only make those changes, the tree would work but there would be no nesting yet. The nesting is achieved by letting each treelist row point to its parent using the <code>b:observe</code> attribute. It is probably most convenient to give every element an ID and refer to that, but you can also use relative paths.</p> <p>A very simple example treelist would look like this:</p> <pre>&lt;g:treelist> &lt;thead> &lt;tr> &lt;th>Column&lt;/th> &lt;/tr> &lt;/thead> &lt;tbody> &lt;g:treelisttr id="tl-1"> &lt;g:treelisttd>Row 1&lt;/g:treelisttd> &lt;/g:treelisttr> &lt;g:treelisttr id="tl-1-1" b:observe="id('tl-1')"> &lt;g:treelisttd>Row 2&lt;/g:treelisttd> &lt;/g:treelisttr> &lt;/tbody> &lt;/g:treelist> </pre> <h2>How to add sub-items</h2> <p>Items can also be added to the tree dynamically. If they are added as children of another node, the other node will automatically become a folder, etcetera.</p> <p>Try it! <a>Click to add a sub-item to the first row <s:event b:on="command"> <s:render b:destination="id('tl-1')" b:mode="after"> <g:treelisttr id="tl-1-1" b:observe="id('tl-1')"> <g:treelisttd>really long subject thingy rea (1)</g:treelisttd> <td>Marijan Milicevic - Backbase</td> <td>15-07-2005, 13:01</td> </g:treelisttr> </s:render> </s:event> </a>. </p> <p>What you do have to take care of however is that the sub-item is placed in the correct location. The easiest way to do this is by using a b:destination that points to its parent, and a b:mode of ‘after’, as the link above does. Alternatively, you could also load the item ‘after’ another item that has the same parent, but that’ll be slightly less easy because you can’t do a convenient lookup by ID.</p> <p>This can be caught in a behaviour as well, for example one like this:</p> <pre>&lt;a g:parentnode="id('1126')"> &lt;s:event b:on="command"> &lt;s:render b:destination="xpath(@g:parentnode)" b:mode="after"> &lt;g:treelisttr id="1127" b:observe="{@g:parentnode}"> &lt;g:treelisttd>Sub-item&lt;/g:treelisttd> &lt;/g:treelisttr> &lt;/s:render> &lt;/s:event> &lt;/a> </pre> <h2>Final notes</h2> <p>With regard to speed, my treelist control is very fast in operation, but the initialisation can take some time if the set of data is too large. So I recommend people to implement an incrementally loading mechanism if they want to put larger amounts of data in this treelist.</p> <p>Alternatively, one could also try to decrease the loading time by getting rid of the control’s construct event. This event mainly consists of determining the nesting (and indentation) of each row, and if you can let the server add that information instead, you should be able to get a significant speed-up.</p> <p>~Grauw</p>