Site Admin
Site Admin Founder of MeaningArticles
67 Views

Laravel Create Hierarchical Dynamic Treeview Menu

Hello Dev.

Nowaday, i will provide an explanation for how can create dynamic multi level menu in laravel we will create instance of multi step dynamic menu in laravel you can simply to make many level dynamic menu in laravel. i will display parents and child menu with nested tree view structure in Laravel software.

on this article i simple create "menus" table and manage end level of parents and child menu with nested tree view structure in Laravel utility. i take advantage of jquery for make tree view layout and child relationship with menu model for hierarchical data. I also add form for create new menu in tree view. I additionally create dynamic drop down menu the use of bootstrap nav.

here following example step of multi level dynamic menu in laravel treeview.


Step 1: Install Application

we are going from scratch, So we require to get fresh Laravel application using bellow command, So open your terminal OR command prompt and run bellow command:

composer create-project --prefer-dist laravel/laravel blog

Database Configuration

In this step, we require to make database configuration, you have to add following details on your .env file.

- Database Username
- Database Password
- Database Name

In .env file also available host and port details, you can configure all details as in your system, So you can put like as bellow:
.env

DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret


Step 2: Create Category Model

In this step we have to create migration and model for menus table using Laravel php artisan command, so first fire bellow command:
After this command you have to put bellow code in your migration file for create menus table.
/database/migrations/2021_09_01_112426_create_menus_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMenusTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('menus', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->integer('parent_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('menus');
    }
}

Now we require to run migration be bellow command:

php artisan migrate

After you have to put bellow code in your model file for create Menu table.
/app/Menu.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Menu extends Model
{
    protected $fillable = ['title','parent_id'];

    public function childs() {
        return $this->hasMany('App\Menu','parent_id','id') ;
    }
}


Step 3: Create Route

In this is step we need to create route for tree menu show layout file, create menu for post method.
route and show dynamic menus.
/routes/web.php

Route::get('menus','[email protected]');
Route::get('menus-show','[email protected]');
Route::post('menus','[email protected]')->name('menus.store');


Step 4: Create Controller

here this step now we should create new controller as MenuController,So run bellow command for generate new controller

php artisan make:controller MenuController

now this step, this controller will manage menu layout and create menu with validation with post request,bellow content in controller file. i added three method in this controller as listed bellow:

1. index()
2. store()
3. show()

/app/Http/Controllers/MenuController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Menu;

class MenuController extends Controller
{
    public function index(){
        $menus = Menu::where('parent_id', '=', 0)->get();
        $allMenus = Menu::pluck('title','id')->all();
        return view('menu.menuTreeview',compact('menus','allMenus'));
    }

    public function store(Request $request)
    {
        $request->validate([
           'title' => 'required',
        ]);

        $input = $request->all();
        $input['parent_id'] = empty($input['parent_id']) ? 0 : $input['parent_id'];
        Menu::create($input);
        return back()->with('success', 'Menu added successfully.');
    }

    public function show()
    {
        $menus = Menu::where('parent_id', '=', 0)->get();
        return view('menu.dynamicMenu',compact('menus'));
    }
}


Step 5: Create View

In this step, we have to create menu folder in total four blade file as listed bellow:

1. menuTreeview.blade.php
2. manageChild.blade.php
3. dynamicMenu.blade.php
4. menusub.blade.php

This both blade file will help to render menu tree structure, so let's create both file view file and put bellow code.
/resources/views/menu/menuTreeview.blade.php

<!DOCTYPE html>
<html>
<head>
   <title>Multi Level Dynamic Menu In Laravel Treeview - meaningarticles.com</title>
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" />
   <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.css">
   <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
   <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
   <link href="/css/treeview.css" rel="stylesheet">
</head>
<body class="bg-dark">
<div class="container">
   <div class="row">
      <div class="col-md-10 offset-md-1 mt-4">
         <div class="card">
            <div class="card-header">
               <h5>Multi Level Dynamic Menu In Laravel Treeview - meaningarticles.com</h5>
            </div>
            <div class="card-body">
               <div class="row">
                  <div class="col-md-6">
                     <h5 class="mb-4 text-center bg-success text-white ">Add New Menu</h5>
                     <form accept="{{ route('menus.store')}}" method="post">
                        @csrf
                         @if(count($errors) > 0)
                                  <div class="alert alert-danger  alert-dismissible">
                                      <button type="button" class="close" data-dismiss="alert">×</button>
                                      @foreach($errors->all() as $error)
                                              {{ $error }}<br>
                                      @endforeach
                                  </div>
                              @endif
                          @if ($message = Session::get('success'))
                           <div class="alert alert-success  alert-dismissible">
                               <button type="button" class="close" data-dismiss="alert">×</button>   
                                   <strong>{{ $message }}</strong>
                           </div>
                        @endif
                        <div class="row">
                           <div class="col-md-12">
                              <div class="form-group">
                                 <label>Title</label>
                                 <input type="text" name="title" class="form-control">   
                              </div>
                           </div>
                        </div>
                        <div class="row">
                           <div class="col-md-12">
                              <div class="form-group">
                                 <label>Parent</label>
                                 <select class="form-control" name="parent_id">
                                    <option selected disabled>Select Parent Menu</option>
                                    @foreach($allMenus as $key => $value)
                                       <option value="{{ $key }}">{{ $value}}</option>
                                    @endforeach
                                 </select>
                              </div>
                           </div>
                        </div>
                        <div class="row">
                           <div class="col-md-12">
                              <button class="btn btn-success">Save</button>
                           </div>
                        </div>
                     </form>
                  </div>
                  <div class="col-md-6">
                     <h5 class="text-center mb-4 bg-info text-white">Menu List</h5>
                      <ul id="tree1">
                         @foreach($menus as $menu)
                            <li>
                                {{ $menu->title }}
                                @if(count($menu->childs))
                                    @include('menu.manageChild',['childs' => $menu->childs])
                                @endif
                            </li>
                         @endforeach
                        </ul>
                  </div>
               </div>
            </div>
         </div>
      </div>
   </div>
</div>
<script src="/js/treeview.js"></script>
</body>
</html>

here following include blade fille
/resources/views/menu/manageChild.blade.php

<ul>
@foreach($childs as $child)
   <li>
       {{ $child->title }}
   @if(count($child->childs))
            @include('manageChild',['childs' => $child->childs])
        @endif
   </li>
@endforeach
</ul>

After This both blade file will help to render dynamic drop down menu view file, so let's create both file view file and put bellow code.
/resources/views/menu/dynamicMenu.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="https://bootstrapthemes.co/demo/resource/bootstrap-4-multi-dropdown-hover-navbar/css/bootstrap-4-hover-navbar.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
</head>
<body class="bg-dark">
<nav class="navbar navbar-expand-md navbar-light bg-light btco-hover-menu">
    <a class="navbar-brand" href="#">meaningarticles.com</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNavDropdown">
        <ul class="navbar-nav">
            @foreach($menus as $menu)
            <li class="nav-item dropdown">
                <a class="nav-link {{ count($menu->childs) ? 'dropdown-toggle' :'' }}" href="https://bootstrapthemes.co" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                   {{ $menu->title }}
                </a>
                <ul class="dropdown-menu " aria-labelledby="navbarDropdownMenuLink">
                  @if(count($menu->childs))
                    @include('menu.menusub',['childs' => $menu->childs])
                  @endif
                </ul>
            </li>
            @endforeach
        </ul>
    </div>
</nav>
<div style="position: absolute; left:2%; top:55%;">
  <h2 class="bg-white p-2 shadow-lg rounded">Multi Level Dynamic Menu In Laravel Treeview - meaningarticles.com</h2>
</div>
</body>
</html>

here following include blade fille
/resources/views/menu/menusub.blade.php

 @foreach($childs as $child)
 <li><a class="dropdown-item {{ count($child->childs) ? 'dropdown-toggle' :'' }}" href="#" style="border:1px solid #ccc;">{{ $child->title }}</a>
       @if(count($child->childs))
          <ul class="dropdown-menu">
              <li>
                 <a class="dropdown-item" href="#" style="position: absolute;">
                       @include('menu.menusub',['childs' => $child->childs])
                    </a>
                </li>
            </ul>
        @endif
   </li>
 @endforeach


Step 6: Add CSS and JS File

In last step, we have to add one css file and one js file for treeview design. I simply use bootsnipp css and js code, so let's create css and js file as following path:
public/css/treeview.css

.tree, .tree ul {
    margin:0;
    padding:0;
    list-style:none
}
.tree ul {
    margin-left:1em;
    position:relative
}
.tree ul ul {
    margin-left:.5em
}
.tree ul:before {
    content:"";
    display:block;
    width:0;
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    border-left:1px solid
}
.tree li {
    margin:0;
    padding:0 1em;
    line-height:2em;
    color:#369;
    font-weight:700;
    position:relative
}
.tree ul li:before {
    content:"";
    display:block;
    width:10px;
    height:0;
    border-top:1px solid;
    margin-top:-1px;
    position:absolute;
    top:1em;
    left:0
}
.tree ul li:last-child:before {
    background:#fff;
    height:auto;
    top:1em;
    bottom:0
}
.indicator {
    margin-right:5px;
}
.tree li a {
    text-decoration: none;
    color:#369;
}
.tree li button, .tree li button:active, .tree li button:focus {
    text-decoration: none;
    color:#369;
    border:none;
    background:transparent;
    margin:0px 0px 0px 0px;
    padding:0px 0px 0px 0px;
    outline: 0;
}

This is require js file
public/js/treeview.js

$.fn.extend({
    treed: function (o) {
      
      var openedClass = 'glyphicon-minus-sign';
      var closedClass = 'glyphicon-plus-sign';
      
      if (typeof o != 'undefined'){
        if (typeof o.openedClass != 'undefined'){
        openedClass = o.openedClass;
        }
        if (typeof o.closedClass != 'undefined'){
        closedClass = o.closedClass;
        }
      };
      
        /* initialize each of the top levels */
        var tree = $(this);
        tree.addClass("tree");
        tree.find('li').has("ul").each(function () {
            var branch = $(this);
            branch.prepend("");
            branch.addClass('branch');
            branch.on('click', function (e) {
                if (this == e.target) {
                    var icon = $(this).children('i:first');
                    icon.toggleClass(openedClass + " " + closedClass);
                    $(this).children().children().toggle();
                }
            })
            branch.children().children().toggle();
        });
        /* fire event from the dynamically added icon */
        tree.find('.branch .indicator').each(function(){
            $(this).on('click', function () {
                $(this).closest('li').click();
            });
        });
        /* fire event to open branch if the li contains an anchor instead of text */
        tree.find('.branch>a').each(function () {
            $(this).on('click', function (e) {
                $(this).closest('li').click();
                e.preventDefault();
            });
        });
        /* fire event to open branch if the li contains a button instead of text */
        tree.find('.branch>button').each(function () {
            $(this).on('click', function (e) {
                $(this).closest('li').click();
                e.preventDefault();
            });
        });
    }
});
/* Initialization of treeviews */
$('#tree1').treed(); 

Now we are ready to run our example so run bellow command so quick run:

php artisan serve

open bellow URL to create menu on your browser:

http://localhost:8000/menus

Now you can open bellow URL to dropdown nav menu on your browser:

http://localhost:8000/menus-show

 i'm hoping it assist you to, thanks for visit my article if you like my article then proportion together with your friend and social platform.