Laravel

Laravel Unlimited Hierarchical Category Tree View

Pinterest LinkedIn Tumblr

Hey, Real Programmer, I am going to share with you how to create a dynamic category tree view structure in Laravel 7 application using jquery. We sometimes require to make tree view structure for category and subcategory.

In this tutorial, I simply create “categories” table and manage end level of parents and child category with nested tree view structure in Laravel application. I use jquery to make tree view layout and child relationship with the category model for hierarchical data. I also add a form for creating a new category in a tree view.

If you are new in laravel then also you can do it simply and also simply customize it because of this tutorial from scratch. You can simple following bellow step, you will get category tree view in your application as bellow preview and also you can check demo.

Step 1: Download laravel 7

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

Go inside of LaravelUnlimitedHierarchicalCategory folder

cd LaravelUnlimitedHierarchicalCategory

Step 2: Run Migration Command

php artisan make:migration create_category_table

After this command, you need to find one file in following path database/migrations and you have to put bellow code in your migration file for create categories table.

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

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

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

Run Migration Command

php artisan migrate

In this step, we are going to generate the model file using the terminal for we need to run below command.

php artisan make:model Category

After creating “categories” table you should create a Category model for categories, so first create the file in this path app/Category.php.

app/Category.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    public $fillable = ['name','parent_id'];
    /**
     * Get the index name for the model.
     *
     * @return string
    */
    public function childs() {
        return $this->hasMany('App\Category','parent_id','id') ;
    }
}

Step 3: Create Route

In this is a step we need to create two routes one for render treeview and second for add new category file. so open your routes/web.php file and add the following route.

routes/web.php

Route::get('category-tree-view',['uses'=>'CategoryController@manageCategory']);
 Route::post('add-category',['as'=>'add.category','uses'=>'CategoryController@addCategory']);

Step 4: Create Controller

In this point, now we should create new controller call CategoryController in this path app/Http/Controllers/CategoryController.php. In this controller we will manage the route method, I added two methods in this controller as listed below:

1) manageCategory()

2) addCategory()

So, copy bellow code and put in your controller file.

app/Http/Controllers/CategoryController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Category;

class CategoryController extends Controller
{
    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function manageCategory()
    {
        $categories = Category::where('parent_id', '=', 0)->get();
        $allCategories = Category::pluck('title','id')->all();
        return view('categoryTreeview',compact('categories','allCategories'));
    }


    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function addCategory(Request $request)
    {
        $this->validate($request, [
        		'name' => 'required',
        	]);
        $input = $request->all();
        $input['parent_id'] = empty($input['parent_id']) ? 0 : $input['parent_id'];
        
        Category::create($input);
        return back()->with('success', 'New Category added successfully.');
    }


}

Step 5: Create View

In this step, we have to create a total of a two-blade file as listed below:

1. categoryTreeview.blade.php

2. manageChild.blade.php

This both blade file will help to render category tree structure, so let’s create both file view file and put the bellow code.

resources/views/categoryTreeview.blade.php

<!DOCTYPE html>
<html>
   <head>
      <title>Laravel Unlimited Hierarchical Category Tree View Example</title>
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" />
      <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css" rel="stylesheet">
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
      <link href="{{ asset('css/treeview.css') }}" rel="stylesheet">
      <style>
         .tree {
         height: 400px;
         overflow: overlay;
         border: 1px solid;
         }
      </style>
   </head>
   <body>
      <div class="container">
         <div class="panel panel-primary">
            <div class="panel-heading">Unlimited Hierarchical Category Tree View</div>
            <div class="panel-body">
               <div class="row">
                  <div class="col-md-6">
                     <h3>Add New Category</h3>
                     <form role="form" id="category" method="POST" action="{{ route('add.category') }}" enctype="multipart/form-data">
                        @csrf
                        <div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
                           <label>Title:</label>
                           <input type="text" id="title" name="title" value="" class="form-control" placeholder="Enter Title">
                           @if ($errors->has('title'))
                           <span class="text-red" role="alert">
                           <strong>{{ $errors->first('title') }}</strong>
                           </span>
                           @endif
                        </div>
                        <div class="form-group {{ $errors->has('parent_id') ? 'has-error' : '' }}">
                           <label>Category:</label>
                           <br>
                           <br>
                           <br>
                           <ul id="tree1">
                              @foreach($categories as $category)
                              <li> <input type="radio"  id="parent_id" name="parent_id" value="{{ $category->id }}">
                                 <label for="parent_id"> {{ $category->title }}</label><br>
                              </li>
                              @if(count($category->childs))
                              @include('category.manageCheckbox',['childs' => $category->childs])
                              @endif
                              @endforeach
                           </ul>
                           @if ($errors->has('parent_id'))
                           <span class="text-red" role="alert">
                           <strong>{{ $errors->first('parent_id') }}</strong>
                           </span>
                           @endif
                        </div>
                        <div class="form-group">
                           <button type="submit" class="btn btn-success">Add New</button>
                        </div>
                     </form>
                  </div>
               </div>
            </div>
         </div>
      </div>
      <!-- Sid -->
      <script src="{{ asset('js/treeview.js') }}"></script>
   </body>
</html>

resources/views/manageCheckbox.blade.php

<ul>
   @foreach($childs as $child)
   <li>
      <input type="radio"  id="{{ $child->id }}" name="parent_id" value="{{ $child->id }}">
      <label for="vehicle1"> {{ $child->title }}</label><br>
      @if(count($child->childs))
      @include('category.manageChildCheckbox',['childs' => $child->childs])
      @endif
   </li>
   @endforeach
</ul>

resources/views/manageChildCheckbox.blade.php

<ul>
   @foreach($childs as $child)
   <li>
      <input type="radio"  id="{{ $child->id }}" name="parent_id" value="{{ $child->id }}">
      <label for="vehicle1"> {{ $child->title }}</label><br>
      @if(count($child->childs))
      @include('category.manageChildCheckbox',['childs' => $child->childs])
      @endif
   </li>
   @endforeach
</ul>

Step 6: Add CSS and JS File

public/css/treeview.css

.tree, .tree ul {

    margin:0;

    padding:0;

    list-style:none

}

.panel-primary > .panel-heading {
    color: #fff;
    background-color: #606ec3;
    border-color: #606ec3;
}

.panel-primary {

    border-color: #606ec3;
    margin: 3%;

}
.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;

}

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();

Step 7:

Now you can run using bellow command:

php artisan serve

Open bellow URL:

http://127.0.0.1:8000

Write A Comment