Categories > TinyButStrong general >

tree menu structures

The forum is closed. Please use Stack Overflow for submitting new questions. Use tags: tinybutstrong , opentbs
By: RwD
Date: 2003-11-18
Time: 21:09

tree menu structures

I would like to know if tbs can generate a tree structure from this

Nodes:
ID    ParentID   Title
1      ---           Main
2      1             Sub1
3      1             Sub2
4      3             sub2.1
5      1             Sub3

Generated tree (code):
<ul>
    <li>Main</li>
    <ul>
        <li>Sub1</li>
        <li>Sub2</li>
        <ul>
            <li>sub2.1</li>
        </ul>
        <li>Sub3</li>
    </ul>
</ul>


Please tell me it can do this!! :)
By: Skrol29
Date: 2003-11-19
Time: 10:59

Re: tree menu structures

Hello Rwd,

If you database system doesn't support hierachical queries, then I don't think this is possible for TBS. You have to prepare the data.

If you have the data sorted and with an extra column like this :
ID    ParentID   Title     Level
1      ---           Main     1
2      1             Sub1    2
3      1             Sub2    2
4      3             sub2.1  3
5      1             Sub3     2
Then TBS can do it.
By: RwD
Date: 2003-11-19
Time: 12:59

Re: tree menu structures

Well, right now I use mySQL and on the previous website system I used multiple queries to get the tree

(So just a select * from table where parentid = id)

is it possible doing it that way?
and (only) if not, how is it done with your level solution??
By: Skrol29
Date: 2003-11-19
Time: 15:26

Re: tree menu structures

Yes finaly it can do it (!!!!!!)
Using clone-blocks and one event function.

This may be slow if you have many lines because the clone-block feature calls multiple queries (one query for each item!).
I did'nt found the way to manage the <ul> yet, but still working on it...

HTML :
********<br>
<li>[blk.tr_name;block=li;p1=0;onformat=m_format]<br>
  [blk.children;htmlconv=no;protect=no]
</li>
<br>
********

PHP :
$src = $TBS->GetBlockSource('blk') ;
$TBS->MergeBlock('blk',$cnx_id,'select tr_id,tr_name from t_test_tree where tr_parent=%p1%') ;
$TBS->Show() ;

//event function
function m_format($BlockName,&$CurrRec) {
  if ($BlockName==='blk') { //allows to by-pass a TBS bug 
    global $src ;
    $CurrRec['children'] = str_replace('p1=0','p1='.$CurrRec[tr_id],$src) ;
  }
}
By: Skrol29
Date: 2003-11-19
Time: 15:40

Re: tree menu structures

The version which displays level :

HTML :
********
<li>[blk.tr_name;block=li;p1=0;onformat=m_format]
<ul>[blk.children;htmlconv=no;protect=no]</ul>
</li>
********

PHP :
$src = $TBS->GetBlockSource('blk') ;
$TBS->MergeBlock('blk',$cnx_id,'select tr_id,tr_name from t_test_tree where tr_parent=%p1%') ;
$TBS->Source = str_replace('<ul></ul>','',$TBS->Source) ; //make html clean
$TBS->Show() ;

//event function
function m_format($BlockName,&$CurrRec) {
  if ($BlockName==='blk') { //allows to by-pass a TBS bug 
    global $src ;
    $CurrRec['children'] = str_replace('p1=0','p1='.$CurrRec[tr_id],$src) ;
  }
}
By: RwD
Date: 2003-11-19
Time: 20:25

Re: tree menu structures

The first method doesn't show a tree over here. I understand what it seems to be trying, but haven't got the faintest clue on where it goes wrong, I do not see any error messages to do trial and error :'(

below are the template, php source and the mySQl dump

html:
<ul>
<br>
<li>{blk.descr;block=li;p1=0;onformat=m_format}<br>
  {blk.children;htmlconv=no;protect=no}
</li>
<br>
</ul>

php:
<?
//event function
function m_format($BlockName, &$CurrRec)
{
    if ($BlockName === 'blk')
    { //allows to by-pass a TBS bug 
        global $src;
        $CurrRec['children']     = str_replace('p1=0', 'p1='.$CurrRec[id], $src) ;
    }
}

//***************
//*    Database includes
var $Host     = "localhost";
var $Database     = "nelliesnellen";
var $User     = "root";
var $Password     = "";

$db_id = mysql_connect($Host, $User, $Password) ;
$db_ok = mysql_select_db($Database, $db_id) ;
//****************

require( 'class-tbs.php' );
$TBS     = new clsTinyButStrong;

$TBS->LoadTemplate('templ.htm');
$src     = $TBS->GetBlockSource('blk');
$TBS->MergeBlock('blk',$db_id,'select id, descr from category where parent_id=%p1%');
$TBS->Show();
?>

MySQL
CREATE TABLE category (
  id int(11) NOT NULL auto_increment,
  parent_id int(11) default NULL,
  order_by int(11) NOT NULL default '999',
  title int(11) NOT NULL default '-1',
  descr int(11) NOT NULL default '-1',
  menu_title int(11) NOT NULL default '-1',
  menu_target varchar(255) default NULL,
  visible enum('0','1') NOT NULL default '0',
  PRIMARY KEY  (id)
) TYPE=MyISAM;

#
# Gegevens worden uitgevoerd voor tabel `category`
#

INSERT INTO category VALUES (1, 0, 999, 4, 5, 6, '', '1');
INSERT INTO category VALUES (2, 1, 999, 7, 8, 9, 'OpenPage?target=webstore', '1');
INSERT INTO category VALUES (5, 1, 999, 19, 20, 21, 'OpenPage?target=infood', '1');
INSERT INTO category VALUES (4, 1, 999, 16, 17, 18, 'OpenPage?target=deliverterms', '1');
By: Skrol29
Date: 2003-11-20
Time: 01:52

Re: tree menu structures

relace
$CurrRec[id]
whith
$CurrRec['id']
and tell me
By: RwD
Date: 2003-11-20
Time: 07:43

Re: tree menu structures

no difference nothing showing

do we have the same tbs version? I have 1.81


I tested the query with p1=0 and it did yield a single row (the main node)
By: mielem
Date: 2003-11-20
Time: 14:21

Re: tree menu structures

Excuse for the intrusion, if you use a table like this:

ID    ParentID   Title     Level
1      ---           Main     1
2      1             Sub1     2
3      1             Sub2     2
4      3             sub2.1   3
5      1             Sub3     2

to obtain...

<ul>
    <li>Main</li>
    <ul>
        <li>Sub1</li>
    </ul>
    <ul>
        <li>Sub2</li>
    </ul>
        <ul><ul>
            <li>sub2.1</li>
        </ul></ul>
    <ul>
        <li>Sub3</li>
    </ul>
</ul>
... where every sublevel is opened and closed each time, you should use tbs_check to choose between alternative format for each row.
By: RwD
Date: 2003-11-20
Time: 15:22

Re: tree menu structures

I think introducing a level element puts redundant data in the database, and the size of the data should be minimized in my case if it is possible.

I prefer the first method, but it doesn't show anything at all!! The exact data on what I did, and what's in my database, can be found in one of the posts above...
By: Skrol29
Date: 2003-11-20
Time: 15:31

Re: tree menu structures

Hello Rwd,

I've tried your info (hmlt+php+data) and it displays something for me.
I'be only modified the PHP code as fallow :
- taked off the "var" prefixe before the variable set
- change require( 'class-tbs.php' ); into require( 'tbs_class.php' );
- add  $tbs_ChrOpen = '{' ; $tbs_ChrClose = '}' ;

Then it displays something well sorted but without level increments.
When I changed the Html part by nesting the [blk.children] field with <ul> and </ul>, then the levels are displayed correctly.
By: RwD
Date: 2003-11-20
Time: 15:54

Re: tree menu structures

can you show me the code? because:

-my tbs class is called class-tbs.php (my preference)
-my $tbs_Chrs already are set to { and }

so the only difference is the var parameter

I also don't understand the nesting part you speak of...

Are we using the same versions of db, tbs and php?
tbs     1.81
php    4.3.4
mysql 3.23.58  (yes, old, but the currrent version of the target server)
By: Skrol29
Date: 2003-11-20
Time: 16:13

Re: tree menu structures

I've tested with :

- TBS 1.81
- MySql 4.0.15 (but it should doesn't matter)
- Php 4.3.3 (but it should doesn't matter)

I can send you the code or put it here, as you want.
By: Skrol29
Date: 2003-11-20
Time: 16:17

Re: tree menu structures

Hello Miele,

I agree with you. I had to work with a big hierachical table some years ago. Database systems rarely propose hierarchical features. So I had to design the database with redondant information (Rwd doesn't like that) in order to have simple queries fast responses.
By: RwD
Date: 2003-11-20
Time: 16:37

Re: tree menu structures

whichever you like best. be sure to remove the SP AM from the address but leave the dot in!! :)

for future reference posting it here will be best
By: mielem
Date: 2003-11-20
Time: 17:20

Re: tree menu structures

I'm glad you agree with me. It seems to me it's the most economical way to to that. The level info can be an enum type, so smaller than that...
By: RwD
Date: 2003-11-20
Time: 19:52

Re: tree menu structures

post your reply ;)

It works, Thanks a lot!! :)
By: RwD
Date: 2003-11-20
Time: 20:40

Re: tree menu structures

what is my advantage of using levels then?
Besides from what you say I need just one query I cannot see what i gain.

Please tell me the other advantages.
By: RwD
Date: 2003-11-20
Time: 20:41

Re: tree menu structures

I want to elaborate on the "It works"

The problem was the var statements, I believe you can only use ehm inside classes, and everything I do is object based, I got confused :P
By: Skrol29
Date: 2003-11-21
Time: 09:46

Re: tree menu structures

Saving level info is good when you have lot of items in the hierarchical data (the tree).

Building the tree representation from only id and parent_id is something a bit complicated that (many) database systems cannot perform. If you have to do the calculation each time you have to display the tree, then it could be slow. That's why saving the result of the calculation (that is order and level) can by good for performance.

For example, look at the tree of messages in the frame on the left of this forum. Levels and order are saved in the table. Eache time a message is added, the tree is updated. This costs a bit more time when adding a message, but in another hand, it need only ONE query to display the full tree.

but if you have only few item to display, then saving levels and order can be as much complicated as calculating it for each display.
By: RwD
Date: 2003-11-21
Time: 11:38

Re: tree menu structures

Well, I builded a system that can load sections of pages without reloading other sections (no chache, temp files nor frames) so I only need to build the tree once for every visitor, I'm ok on that part.

Tracking and comparing the data on other sites (not using a template engine) with the same technique show it is easier on the db allready. True, a single query would bring traffic back even further. But except for the tree it is allready minimized to loading everything else with a single query per table I use. (not counting language tables (from where the desrc field gets it's content for example))

So all in all I'm not worrying about traffic or load times. I also support all browsers versions4 and up ;)

-------------------
I do have a follow up question:
Can the first result found be treated differently? in fact, can it be ommitted entirely.

Now the tree starts with a single node, containing the tree. but the first nod is more or less implied by all it's children and I don't want it.

Changing p1=0 to p1=1 didn't do the trick where I thought that oughta work. I'm getting better at TBS every day, but these things are still above my understanding of how it works.

(perhaps in the future I will look into the code, disecting it until I now every little detail, but I'm under pressure, don't have much time to start figuring things out) (I do promise that the rest of the website wil use simple template functionality and I won't keep asking questions all the time ;))
By: Skrol29
Date: 2003-11-24
Time: 11:13

Re: tree menu structures

> Can the first result found be treated differently? in fact, can it be ommitted entirely.

I think it should work with changing p1=0 to p1=1 in the block but also in the m_format() event function.
By: RwD
Date: 2003-11-24
Time: 22:07

Re: tree menu structures

Hmmz, there we go :P

I only changed it in the template |(
By: RwD
Date: 2004-01-26
Time: 13:20

Re: tree menu structures

Hi, a while ago you posted this solution to my problem :D
still works perfectly, BUT, new version of TBS I desperately need to use that version (for the PHP support)

However, it will not run this example, I get a warning saying that key 'children' is not in the array

It refers to this part:
[blk.children;htmlconv=no;protect=no]
and indeed that field is not in the database, but it isn't either with the old version of tbs, and there it works!!

Hopefully this takes just a little change, because I allready missed the deadline due to my lack of testing on the server (otherwise I would have noticed it before ofcourse) I did do a quick study to the changes, but didn't really see anything that explains why it isn't working anymore.

Does anyone know what to change? or where the change is explained in the documentation??

Skrol 's Solution:
HTML :
<li>[blk.tr_name;block=li;p1=0;onformat=m_format]
<ul>[blk.children;htmlconv=no;protect=no]</ul>
</li>


PHP :
$src = $TBS->GetBlockSource('blk') ;
$TBS->MergeBlock('blk',$cnx_id,'select tr_id,tr_name from t_test_tree where tr_parent=%p1%') ;
$TBS->Source = str_replace('<ul></ul>','',$TBS->Source) ; //make html clean
$TBS->Show() ;

//event function
function m_format($BlockName,&$CurrRec) {
  if ($BlockName==='blk') { //allows to by-pass a TBS bug 
    global $src ;
    $CurrRec['children'] = str_replace('p1=0','p1='.$CurrRec[tr_id],$src) ;
  }
}

My DB fields (MySQL)
CREATE TABLE category (
  id int(11) NOT NULL auto_increment,
  parent_id int(11) default NULL,
  order_by int(11) NOT NULL default '999',
  title int(11) NOT NULL default '-1',
  descr int(11) NOT NULL default '-1',
  menu_title int(11) NOT NULL default '-1',
  menu_target varchar(255) default NULL,
  visible enum('0','1') NOT NULL default '0',
  PRIMARY KEY  (id)
) TYPE=MyISAM;

#
# Gegevens worden uitgevoerd voor tabel `category`
#

INSERT INTO category VALUES (1, 0, 999, 4, 5, 6, '', '1');
INSERT INTO category VALUES (2, 1, 999, 7, 8, 9, 'OpenPage?target=webstore', '1');
INSERT INTO category VALUES (5, 1, 999, 19, 20, 21, 'OpenPage?target=infood', '1');
INSERT INTO category VALUES (4, 1, 999, 16, 17, 18, 'OpenPage?target=deliverterms', '1');
By: Skrol29
Date: 2004-01-26
Time: 17:50

Re: tree menu structures

Hi RwD,

Your table structure doesn\'t fit with you template and Php code.
But that\'s not the problem.

First you have to change the parameter \'onformat\' with \'onsection\'.
That\'s something new with TBS 1.90 because onformat was ambigious between fields and blocks.

After that, you have to fix a small mistake in your m_format() function.
It should be $CurrRec[\'tr_id\'] instead of $CurrRec[tr_id].

After those changes, you will still have error messages.
This is because there is a new infinit loop check in the merge process whcih ends your children loop :(
That is at line #1243 in the tbs_class.php file.
There is: $Pos = tbs_Locator_Replace(...) ;
If you instert the line: $Pos = $BlockLoc->PosBeg ;
just after #1243 then your template will run properly.

I gonna study your case to see if I have to change the code and publish a new release. But there is probably a smart issue that doesn\'t need to change any code. I\'ll be back on this.
By: Skrol29
Date: 2004-01-26
Time: 19:39

Re: tree menu structures

Ok, the fix is available for download.
That's TBS 1.92.
By: RwD
Date: 2004-01-27
Time: 08:38

Re: tree menu structures

Thanks, it indeed works now with that extra line added a after #1243

I had allready changed the onformat to onsection, but forgot to mention that when I posted your code. (That was one of the changes that I did find between versions) I just would have never found that infinite loop check thing I guess :)

thanks again
By: RwD
Date: 2004-01-27
Time: 08:41

Re: tree menu structures

What does the fix fix exactly?

change of behavior when using parameter 'onsection'.
If you use parameter 'onsection' on a block to change the current section definition, then TBS doesn't take the change in account while it used to with version 1.8x (using parameter 'onformat'). With this fix, the behavior is the the same as version 1.8x.

Does that mean that the infinite loop check didn't take into acount that the loop will end because the block code is being altered as you proceed trough? (Thats the only thing I could come up with with my sleepy head yesterday 4 hours of sleep in between two 21 hour days :P)
By: Skrol29
Date: 2004-01-27
Time: 14:17

Re: tree menu structures

:)

With 1.8x, when a block is merged, TBS search for the next section starting from the *beginning* of the previous merged block's section.

With 1.91, when a block is merged, TBS search for the next section starting from the *end* of the previous merged block's section.

At first that was not a bug. That was a security feature to prevent from any infinit loop when merging a block.
But this security makes your kind of process impossible. So that a kind of compatibility bug because behavior between 1.8x and 1.91 is different.

I'll try to make the support page clearer.
By: RwD
Date: 2004-01-27
Time: 16:20

Re: tree menu structures

haha, ok, I see

If we keep on going in this way you'll soo have version 2 out ;)
By: TheIdeaMan
Date: 2004-11-30
Time: 14:10

Re: tree menu structures

Ok, so this is a really old thread, but the information was still very helpful.

I was able to modify the code (for 2.0) for creating a ul/li tree. After doing so, I wanted to see if I could integrate a sub-block in the midst of the tree. I haven't been able to get it to work yet, and I was wondering if anyone here had some suggestions.

The code I have thus far is below:

PHP:
$src = $TBS->GetBlockSource('blk');
$sql = "SELECT file_folder_id, file_folder_name FROM file_folders WHERE file_folder_parent=%p1%";
$TBS->MergeBlock('blk',$cnx_id, $sql);
$TBS->Show();

//event function
function m_format($BlockName, &$CurrRec) {
  if ($BlockName==='blk') { //allows to by-pass a TBS bug
    global $src, $TBS;
    $CurrRec['children'] = str_replace('p1=0','p1='.$CurrRec['file_folder_id'],$src) ;
    $sql2 = "SELECT file_name, file_size FROM files WHERE file_folder=%p2%";
    $TBS->MergeBlock('subblk',$cnx_id, $sql2);
  }
}

HTML:
<ul>
<li>[blk.file_folder_name;block=li;p1=0;onsection=m_format]
  <ul>[blk.children;htmlconv=no;protect=no]
      <table>
     <tr><td>[subblk.file_name;block=td;p2=[blk.file_folder_id];noerr]</td><td>[subblk.file_size;block=td;]</td></tr>
     </table>
  </ul>
</li>
</ul>

I get this error...
TinyButStrong Error (MergeBlock [subblk]): Unsupported variable type : 'NULL'.
as many times as there are main block entries.

The tree itself comes out fine, but rather than merging the subblk content, I get the subblk code where the merge should have been.

As you can see from the code, I'm trying to build a file folder structure that also displays a list of files in that folder in a table.

Thanks in advance for any and all help.
By: Skrol29
Date: 2004-12-01
Time: 02:40

Re: tree menu structures

Hello,

First $cnx_id is not defined in your function.
That's why you've got this message.

But also, I think you've swaped property 'onsection' with 'onformat'.
I think it should be 'onsection' here. Before version 1.90 'onsection' was called 'onformat' too. That's why you've got this name in the top message of this thread. You've also got change the syntax of the function.

And then, I must say I think your code won't work because of the $TBS->MergeBlock() inside the m_format() function. If you're merging a part of the template when antoher part is beeing merged too, it probably  make something strange.
By: Coyote
Date: 2007-06-20
Time: 15:40

Re: tree menu structures

I can't make it work with TBS 3.2.0.

Can you post a new working example...

thanks
By: Skrol29
Date: 2007-06-20
Time: 18:55

Re: tree menu structures

Ok, I'm preparing a new post that will be available in the Tip&Tricks forum.
By: Skrol29
Date: 2007-06-24
Time: 01:07

Re: tree menu structures

Hi,

A new post is available about this subject in the Tip&Trick forum.

By: sheepy
Date: 2007-06-27
Time: 12:26

Re: tree menu structures

Is there any way to generate the same html ul/li tree structure in a single merge assuming I can include each row's tree level and have the rows comes out in order?

e.g.
id,level,name,child#,parent_id,and info like that...
1,0,--Electronics ,2,0
3,1,----CED7000 ,0,1
4,1,----CED8000 ,2,1
5,2,------CED8001 ,0,4
6,2,------CED8002 ,0,4
2,0,--Bags ,0,0

I started moving to modified pre order tree about half a year ago, which allows me to build the whole tree of part of if from a single query, and I can then process the raw data (e.g. merge to a select box) or turns it into a hierarchy of arrays with a single pass of the data.  It is rather complicated, but usually more efficient.

So far when I want the ul/li structure I'll get the data in array tree form and use a recursive function to do what I want, but naturally it'd be much better if I can push the logic to tbs template.