George Whitcher

Dad, Web Developer, Software Engineer, Graphic Artist, Snowboarder, Musician, Gamer, Nerd

Bootstrap Dynamic Multi-Level Drop Downs

Posted in Code
March 28, 2017 01:24:19 PM
Published by
Leave your thoughts

If you can't tell from looking at my projects I love Bootstrap.  It makes frontend development so much quicker and easier.  Sometimes though you run into issues.  Most recently one I ran into was getting multi-level drop downs to work on Bootstrap and dynamically create them from the database.

First you need to create the database.  You can use the following database query or setup your own fields.  Just make sure and map them to $nav_array if you do.  The important field to note here is parent_id.  This is the field that will make your navigation item a sub item of ID chosen.  So for instance say you had two items (id => 1, title => 'Apple', parent_id => 0), (id => 2, title => 'Orange', parent_id => 1).  Note the parent_id 1 in Orange?  That is what will make Orange a sub item of Apple.

CREATE TABLE `DATABASE_HERE`.`DATABASE_TABLE_HERE` ( `id` INT NOT NULL AUTO_INCREMENT , `parent_id` INT NOT NULL , `url` TEXT NOT NULL , `target` VARCHAR(255) NOT NULL , `title` TEXT NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;

You can also fill in the database with some test data if you like.

INSERT INTO `DATABASE_TABLE_HERE` (`id`, `parent_id`, `url`, `target`, `title`) VALUES (NULL, '0', '#', '', 'Test 1')
INSERT INTO `DATABASE_TABLE_HERE` (`id`, `parent_id`, `url`, `target`, `title`) VALUES (NULL, '1', '#', '', 'Test 2')
INSERT INTO `DATABASE_TABLE_HERE` (`id`, `parent_id`, `url`, `target`, `title`) VALUES (NULL, '2', '#', '', 'Test 3')
INSERT INTO `DATABASE_TABLE_HERE` (`id`, `parent_id`, `url`, `target`, `title`) VALUES (NULL, '3', '#', '', 'Test 4')

Now in your script pull all the information from the table you created.  This can be different depending on how you pull your data but this is a good general example.

$con = mysqli_connect("localhost","my_user","my_password","DATABASE_HERE");
$main_navigation = mysqli_query($con,"SELECT * FROM DATABASE_TABLE_HERE");

Next is the functions.  These are a couple functions I modified to work with a dynamic list.  With out going into to much detail this will tell if it is a top level item or a sub level item.  With this you can infinitely make drop downs in your navigation.  Before you go testing though you need to add your CSS and call your functions.

//Navigation
function prepareList(array $items, $pid = 0) {
    $output = array();
    foreach ($items as $item) {
        if ((int) $item['parent_id'] == $pid) {
            if ($children = prepareList($items, $item['id'])) {
                $item['children'] = $children;
            }
            $output[] = $item;
        }
    }
    return $output;
}
function nav($menu_items, $child = false, $level = 0){
    $level++;
    $output = '';
    if (count($menu_items)>0) {
        $output .= ($child === false) ? '<ul class="nav navbar-nav">' : '<ul class="dropdown-menu">' ;
        foreach ($menu_items as $nav_item) {
            //Target
            if(!empty($nav_item['target'])) {$nav_target = 'target="'.$nav_item['target'].'"';} else {$nav_target = "";}

            //Children
            if (isset($nav_item['children'])) { $children = 1; } else { $children = 0; }
            
            //Nav output
            if($children == 1 && $level == 1) {
                $output .= '<li class="dropdown">';
                $output .= '<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" href="'.$nav_item['url'].'" '.$nav_target.'>'.$nav_item['title'].'</a>';
            } elseif($children == 1 && $level > 1) {
                $output .= '<li class="dropdown-submenu">';
                $output .= '<a class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false" href="'.$nav_item['url'].'"'.$nav_target.'>'.$nav_item['title'].'</a>';
            } else {
                $output .= '<li '.nav_active($nav_item['url']).'>';
                $output .= '<a href="'.$nav_item['url'].'" '.$nav_target.'>'.$nav_item['title'].'</a>';
            }
            
            //loop
            if ($children == 1) {
                $output .= nav($nav_item['children'], true, $level);
            }
            
            $output .= '</li>';
        }
        $output .= '</ul>';
    }
    return $output;
}

Include this CSS into your CSS file.  This will make the multi-level drop downs work.

/* Nav */
.dropdown-submenu{
    position:relative;
}
.dropdown-submenu > .dropdown-menu {
    top:0;
    left:100%;
    margin-top:-6px;
    margin-left:-1px;
    -webkit-border-radius:0 6px 6px 6px;
    -moz-border-radius:0 6px 6px 6px;
    border-radius:0 6px 6px 6px;
}
.dropdown-submenu:hover > .dropdown-menu{
    display:block;
}
.dropdown-submenu > a:after{
    display:block;
    content:" ";
    float:right;
    width:0;
    height:0;
    border-color:transparent;
    border-style:solid;
    border-width:5px 0 5px 5px;
    border-left-color:#cccccc;
    margin-top:5px;
    margin-right:-10px;
}
.dropdown-submenu:hover > a:after{
    border-left-color:#ffffff;
}
.dropdown-submenu .pull-left{
    float:none;
}

Now it is time to show your navigation.  Calling your data with the $main_navigation we created in the beginning you will be able to display your data.

//Show Navigation
<nav class="navbar navbar-inverse">
<div class="container-fluid">
    <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
    </div>
    <div id="navbar" class="navbar-collapse collapse">
        <?php
        $nav_array = array();
        foreach ($main_navigation as $nav_item) {
            $nav_array[] = array('id' => $nav_item->id, 'parent_id' => $nav_item->parent_id, 'url' => $nav_item->url, 'target' => $nav_item->target, 'title' => $nav_item->title);
        }
        $tree = prepareList($nav_array);
        echo nav($tree);
        ?>
    </div>
</div>
</nav>

View your page now and you should see your bootstrap navigation with multi-level drop downs.

Article written by:

Hi! My name is George Whitcher and I am a developer from the South Shore of MA.  When I am not busy being a dad I like to play video games, play/write music, snowboard, and skateboard.