0

I'm trying to create a function for a hierarchical navigational menu bar.

I want to be able to have something like this...

<ul id="navigation">
<li><a href="#">Menu Item 1</a></li>
<li><a href="#">Menu Item 2</a></li>
    <ul>
        <li><a href="#">Sub Menu Item 1</a></li>
        <li><a href="#">Sub Menu Item 1</a></li>
    </ul>
<li><a href="#">Menu Item 3</a></li>
<li><a href="#">Menu Item 4</a></li>
</ul>

I'm using this function, but it's not working properly like I'd like it to. It's showing the main parent links, but not the child links.

function build_navbar($pid,$sub=0)
{
    global $db;

    $query = $db->simple_select("navbar", "*", "pid='".$pid."'", array("order_by" => "disporder"));
    $menu_build = "<ul id=\"navigation\">\n";
    while($menu = $db->fetch_array($query))
    {   
        if($sub == 1)
        {
           $menu_build .= "<ul>\n";
           $menu_build .= "<li><a href=\"#\">".$menu['title']."</a></li>\n";
           $menu_build .= "</ul>\n";
        }
        else
        {
           $menu_build .= "<li><a href=\"#\">".$menu['title']."</a></li>\n";
        }
        build_navbar($menu['id'],1);
    }
    $menu_build .= "</ul>\n";

    return $menu_build;
}

Perhaps someone can help me fix this? Thanks.

--- New Update ---

Andy Groff, this is what your code is outputting:

<ul id="navigation">
    <li><a href="#">Home</a></li>
    <ul>
        <li><a href="#">Child Link</a></li>
        <li><a href="#">Child 2</a></li>
    </ul>
    <li><a href="#">Parent</a></li>
</ul>

However, I need it modified so it'll output like this:

<ul id="navigation">
    <li><a href="#">Home</a>
        <ul>
            <li><a href="#">Child Link</a></li>
            <li><a href="#">Child 2</a></li>
        </ul>
    </li>
    <li><a href="#">Parent</a></li>
</ul>

This is what it is outputting now, Andy:

<ul id="navigation">
    </li>
    <li><a href="#">Home</a>
    </li>
    <ul>
        <li>
        <a href="#">Child Link</a>
        </li>
        <li><a href="#">Child 2</a>
    </ul>
    </li>
    <li><a href="#">Parent</a>
</ul>
5
  • Could you show us what is it outputting? Commented Apr 11, 2011 at 23:38
  • Sure. I've updated my question post. Commented Apr 11, 2011 at 23:44
  • Could you give the schema for your database? Commented Apr 11, 2011 at 23:46
  • Okay, I've added the database schema to the post. Commented Apr 11, 2011 at 23:50
  • you should use jQuery UI with ajax Commented Apr 12, 2011 at 0:07

2 Answers 2

1

I think your problem could have something to do with the fact that your function is recursive, but the string you're building gets reset at the top of your function each time, instead of being passed into the function again. Also, I don't see anywhere that sub will get set back to zero for your final iteration. Additionally, it seems like you shouldn't need to query for each individual row. It would be more effective to query once and build the whole menu. I think the recursion can be ditched. Also, I would recommend storing a "sub" flag in your data, instead of using some hard to understand php logic as to whether or not a given row is a sub menu. I made modifications based of these concepts, no idea if it works or not though since I don't have/want to create the data to test it:

function build_navbar()
{
    global $db;
    //first things first, i'd recommend putting a "sub" flag in your database. This example will use it.

    //start off by getting all of the rows. No need for recursion.
    $query = $db->simple_select("navbar", "*", "1", array("order_by" => "disporder"));
    $menu_build = "<ul id=\"navigation\">\n";

    //keep track of what level we're at
    $level = 1;

    while($menu = $db->fetch_array($query))
    {
      //get sub from data
      $sub = $menu['sub']

      //we need to go back to root level
      if($sub == 0 && $level == 2){
        $level--;
        $menu_build .= "</ul></li>\n";
      }
      else $menu_build .= "</li>\n";

      //we need to go up one level
      if($sub == 1 && $level == 1)
      {
        $level++;
        $menu_build .= "<ul><li>\n";
      }
      else $menu_build .= "<li>";
      //always print out a link
      $menu_build .= "<a href=\"#\">".$menu['title']."</a>\n";
    }
    $menu_build .= "</ul>\n";

    return $menu_build;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your code! It seems to work perfectly, however, I need one modification which I can't seem to get working. Please see my first post for info. Thanks.
That unfortunately didn't work. See my edit for what it's outputting.
0

UPDATE:

Try this:

function build_navbar($pid, $sub=0)
{
    global $db;

    $class = $sub ? "sub" : "navigation";

    $menu_build = "<ul class=\"$class\">\n";

    $query = $db->simple_select("navbar", "*", "pid='".$pid."'");
    while($menu = $db->fetch_array($query))
    {
        $menu_build .= "<li><a href=\"#\">".$menu['title']."</a>\n";

        // build child links
        $menu_build .= build_navbar($menu['id'],1);
    }

    $menu_build .= "</ul>";

    return $menu_build;
}

What we are doing here, is allowing each function to build a <ul><li> group, the $sub variable will determine what the ID of the <ul> will be, allowing you to theme each ul differently.


EDIT:

I found it!

this line

build_navbar($menu['id'],1);

needs to be changed to this:

$menu_build = build_navbar($menu['id'],1);

It looks like it should work to me.

What I would do is add some echo statements displaying the SQL query that is being executed each time, then you can copy that into phpmyadmin (or what ever db browser you use). See if it also returns a null result. If it does, there might be something wrong with your data as well.

so for example:

echo "SELECT FROM navbar * WHERE pid='$pid' ORDER_BY disporder;<br>";

6 Comments

$sub is assigned when the function is called, isn't it? 0 initially, then 1 when it is a submenu.
oh, good call, how did I miss that in the function call? good times
does the "sub" query get rows if you run in in phpmyadmin?
@ohmusama: Thanks, that did work, however, I have one more issue I need solved. Please see my update on my post. Thanks!
I kind of assumed that would be the case. Try adding the sub data and using my function. It will give you a lot more flexibility for how you organize things in the future.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.