Results 1 to 11 of 11

Thread: Multi-level menu

  1. #1

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Multi-level menu

    Hi

    I have a multilevel menu, like in the code block below. This menu is represented like nested <ul>s and <li>s
    Code:
    1
    2
       2.I
       2.II
    3
       3.I
          3.I.i
          3.I.ii
       3.II
    1. How would you store that in a database? 2. How would you generate the <ul>s and <li>s needed to build that menu structure using Smarty template engine?

    I only want to use standard Smarty functions, and I don't want to use template inclusion based recursion as that's too slow.

    Any help on either 1, 2, or both is greatly appreciated

    EDIT: I should point out that the menu structure is rather dynamic with stuff being added and removed from anywhere in the structure all the time. So both the database structure and the template needs to be able to handle that.
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

  2. #2

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Re: Multi-level menu

    Currently I'm storing each menu item as a row in a table with info about its name, its parent and whether it has children or not.

    Code to generate the menu looks like this:
    PHP Code:
    {assign var='current_nav_parent' value='-root-'}
    {foreach 
    from=$navigation item=nav}
        {if 
    $current_nav_parent ne $nav.parent}
            </
    ul>
            </
    li>
        {/if}
        <
    li><a href="#">{$nav.name}</a>
        {if 
    $nav.has_children}
            {
    assign var='current_nav_parent' value=`$nav.name`}
            <
    ul>
        {else}
            </
    li>
        {/if}
    {/foreach} 
    The problem is that it doesn't properly close all elements.

    Example html output:
    HTML Code:
    <ul>
    	<li><a href="#">1</a></li>
    	<li><a href="#">2</a></li>
    	<li><a href="#">3</a>
    		<ul>
    			<li><a href="#">3.I</a>
    				<ul>
    					<li><a href="#">3.I.i</a></li>
    					<li><a href="#">3.I.ii</a></li>
    				</ul>
    			</li>
    			<li><a href="#">3.II</a></li>
    		</ul>
    As you can see there's a missing </li> and a missing <ul>. It will have that problem whenever it needs to jump two levels or more at once
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

  3. #3
    VBA Nutter visualAd's Avatar
    Join Date
    Apr 2002
    Location
    Ickenham, UK
    Posts
    4,906

    Re: Multi-level menu

    Use a function to generate the list, then you can have unlimited depth. The reason for your closing tags not appearing is because you did not incude them.
    PHP || MySql || Apache || Get Firefox || OpenOffice.org || Click || Slap ILMV || 1337 c0d || GotoMyPc For FREE! Part 1, Part 2

    | PHP Session --> Database Handler * Custom Error Handler * Installing PHP * HTML Form Handler * PHP 5 OOP * Using XML * Ajax * Xslt | VB6 Winsock - HTTP POST / GET * Winsock - HTTP File Upload

    Latest quote: crptcblade - VB6 executables can't be decompiled, only disassembled. And the disassembled code is even less useful than I am.

    Random VisualAd: Blog - Latest Post: When the Internet becomes Electricity!!


    Spread happiness and joy. Rate good posts.

  4. #4

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Re: Multi-level menu

    Quote Originally Posted by visualAd
    Use a function to generate the list, then you can have unlimited depth.
    How do I do that with Smarty?
    Quote Originally Posted by visualAd
    The reason for your closing tags not appearing is because you did not incude them.
    Yeah, that's because I don't know how to make smarty generate the extra needed </ul> and </li>. If somebody does know, please help me
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

  5. #5
    VBA Nutter visualAd's Avatar
    Join Date
    Apr 2002
    Location
    Ickenham, UK
    Posts
    4,906

    Re: Multi-level menu

    You do it using an include file:
    nav.tpl
    Code:
    {foreach from=$navigation item=nav}
    <ul>
        <li>
            <a href="#">{$nav.name}</a>
            {if $nav.has_children}
                {include current_nav_parent=$nav.value file=navlist.tpl}
            {/if}
        </li>
    </ul>
    {/foreach}
    From the main file:
    Code:
    {include file=nav.tpl current_nav_parent='-root-' navigation=$navigation}
    Last edited by visualAd; Jun 12th, 2007 at 07:58 AM.
    PHP || MySql || Apache || Get Firefox || OpenOffice.org || Click || Slap ILMV || 1337 c0d || GotoMyPc For FREE! Part 1, Part 2

    | PHP Session --> Database Handler * Custom Error Handler * Installing PHP * HTML Form Handler * PHP 5 OOP * Using XML * Ajax * Xslt | VB6 Winsock - HTTP POST / GET * Winsock - HTTP File Upload

    Latest quote: crptcblade - VB6 executables can't be decompiled, only disassembled. And the disassembled code is even less useful than I am.

    Random VisualAd: Blog - Latest Post: When the Internet becomes Electricity!!


    Spread happiness and joy. Rate good posts.

  6. #6

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Re: Multi-level menu

    Quote Originally Posted by McCain
    I don't want to use template inclusion based recursion as that's too slow.
    Isn't that what you are suggesting?
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

  7. #7
    VBA Nutter visualAd's Avatar
    Join Date
    Apr 2002
    Location
    Ickenham, UK
    Posts
    4,906

    Re: Multi-level menu

    I've never found it slow. you have to use some kind of recursion, even if its a function for that kind of thing. I suppose if you are only ever going to have one level of depth you won't require it.

    You should make sure template caching is enabled though.
    PHP || MySql || Apache || Get Firefox || OpenOffice.org || Click || Slap ILMV || 1337 c0d || GotoMyPc For FREE! Part 1, Part 2

    | PHP Session --> Database Handler * Custom Error Handler * Installing PHP * HTML Form Handler * PHP 5 OOP * Using XML * Ajax * Xslt | VB6 Winsock - HTTP POST / GET * Winsock - HTTP File Upload

    Latest quote: crptcblade - VB6 executables can't be decompiled, only disassembled. And the disassembled code is even less useful than I am.

    Random VisualAd: Blog - Latest Post: When the Internet becomes Electricity!!


    Spread happiness and joy. Rate good posts.

  8. #8

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Re: Multi-level menu

    Another reason that I'm trying to avoid recursion is that I think it might be too hard for a web designer to understand. I'm guessing that {if} is no problem to understand. {section}/{foreach} might take some getting used to. But functions and recursion is probably too much programing, don't you think?
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

  9. #9

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Re: Multi-level menu

    I'm working on a solution where the information needed to generate the right amounts of closing tags is embedded in the array I'm looping over. We'll see how that works out. If it isn't any good I'll try your code.
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

  10. #10
    VBA Nutter visualAd's Avatar
    Join Date
    Apr 2002
    Location
    Ickenham, UK
    Posts
    4,906

    Re: Multi-level menu

    You could always assign a custom function. That way the developer need not know you have used recursion or be concerned that you did or not
    PHP || MySql || Apache || Get Firefox || OpenOffice.org || Click || Slap ILMV || 1337 c0d || GotoMyPc For FREE! Part 1, Part 2

    | PHP Session --> Database Handler * Custom Error Handler * Installing PHP * HTML Form Handler * PHP 5 OOP * Using XML * Ajax * Xslt | VB6 Winsock - HTTP POST / GET * Winsock - HTTP File Upload

    Latest quote: crptcblade - VB6 executables can't be decompiled, only disassembled. And the disassembled code is even less useful than I am.

    Random VisualAd: Blog - Latest Post: When the Internet becomes Electricity!!


    Spread happiness and joy. Rate good posts.

  11. #11

    Thread Starter
    Fanatic Member McCain's Avatar
    Join Date
    Jan 2002
    Location
    Sweden/Denmark
    Posts
    802

    Re: Multi-level menu

    I've got it working

    This is the template code:
    PHP Code:
    <div id="nav">
        <
    h1>Navigation</h1>
        <
    ul>
            {foreach 
    from=$navigation item=nav}
                <
    li><a href="#">{$nav.name}</a>
                {if 
    $nav.has_children}
                    <
    ul>
                {else}
                    </
    li>
                {/if}

                {foreach 
    from=$nav.leveldiff item=level}
                    </
    ul>
                    </
    li>
                {/foreach}
            {/foreach}
        </
    ul>
    </
    div
    I'm pretty satisfied with how that look. The code used for generating the php array from the database however I'm not as pleased with. Tbh I think it's pretty ugly

    Any help in cleaning up the following code is much appreciated
    PHP Code:
    public function generateMenu() {
        if (!
    $this->sql->query('SELECT * FROM navigation WHERE parent="-root-" ORDER BY `index` DESC')) {
            echo 
    $this->sql->getError() . "<br>\n";
        }

        
    $stack = array();
        
    $menu = array();

        while (
    $this->sql->next(SQL_ASSOC)) {
            
    array_push($stack$this->sql->getRecord());
        }

        while (
    $stack) {
            
    $data array_pop($stack);
            if (
    $data['has_children']) {
                if (!
    $this->sql->query('SELECT * FROM navigation WHERE parent="' $data['name'] . '" ORDER BY `index` DESC')) {
                    echo 
    $this->sql->getError() . "<br>\n";
                }

                while (
    $this->sql->next(SQL_ASSOC)) {
                    
    array_push($stack$this->sql->getRecord());
                }
            }

            
    $data['leveldiff'] = array();
            if (
    count($menu) > 0) {
                
    $leveldiff intval($menu[count($menu) - 1]['level']) - intval($data['level']);

                if (
    $leveldiff 0) {
                    
    $menu[count($menu) - 1]['leveldiff'] = array_fill(0$leveldiff'*');
                }
            }

            if (
    count($stack) == && $data['level'] > 0) {
                
    $data['leveldiff'] = array_fill(0$data['level'], '*');
            }

            
    array_push($menu$data);
        }

        return 
    $menu;

    As you can probably tell I'm using a custom database class, but I hope you can understand what the code does anyway.
    Never argue with fools, they will only drag you down to their level, and beat you with experience.

    Q: How do you tell an experienced hacker from a novice?
    A: The latter thinks there's 1000 bytes in a kilobyte, while the former is sure there's 1024 meters in a kilometer

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width