Laravel Unlimited Hierarchical Category Tree View

By | June 8, 2019

This tutorial is about the Laravel Unlimited Hierarchical Category Tree View. You can use this code for an unlimited hierarchical category in the admin panel and front-end. Same as Magento’s category hierarchy.

The first step you need to install the fresh latest version of Laravel in your local system for that follow the previous tutorial of CodesCompanion How to install Laravel 5.X

Follow this tutorial and install the fresh Laravel in your system.

Create and Migrate Category Table

In this step, we are going to create a category table using the terminal. For that run below command in your terminal.

php artisan make:migration create_category_table

After running this it will look like this.

Laravel Unlimited Hierarchical Category Tree View - category-table
Terminal command

This will create the migration table file in the “app/database/migrations” folder. Now we are going to open that file and you will see that this file already has this code and the below code will generate automatically.

<?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('category', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
        });
    }

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

We are going to modify that code and the final output will look like this.

<?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('title');
            $table->integer('parent_id');
            $table->timestamps();
        });
    }

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

After update this file we need to migrate this table to the database for that run below code.

php artisan migrate

This will generate the table name “categories” in the database.

Create Model file

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

This will create the model file inside the app folder as “app/Category.php” and this file will look like below.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    //
}

Now update this file with the same as below code.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
      public $fillable = ['title','parent_id'];

    /**

     * Get the index name for the model.

     *

     * @return string

     */

    public function childs() {

        return $this->hasMany('App\Category','parent_id','id') ;

    }
}

Create Route

Add these two routes into routes file named “routes/web.php“.

Route::get('category-tree-view','CategoryController@manageCategory')->name('category-tree-view');
Route::post('add-category','CategoryController@addCategory')->name('add.category');

Create Controller

In this step, we are going to create a controller file for Category for that we are going to run this command in the terminal.

php artisan make:controller CategoryController

This will create the CategoryController.php file at “app/Http/Controllers” and it will look like this.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class CategoryController extends Controller
{
    //
}

The next step is to update this above code that is inside the controller file. And after adding a new code this final file will look like the below code.

<?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::all();

        return view('category.categoryTreeview',compact('categories','allCategories'));
    }


    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */

    public function addCategory(Request $request)
    {
        $this->validate($request, [
            'title' => '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.');

    }
}

Create View

Now we are going to create a view file so let’s create a category folder.

In this step, we are going to create a view file and folder so let’s create a “Category” folder first inside the “app/resources/view” folder.

In that folder, we will create two files named “categoryTreeview.blade.php” and “manageChild.blade.php” so the final directory structure would be “/var/www/html/laravel-hierarchical-category/resources/views/category/manageChild.blade.php” like this.

This view will exactly show the Laravel Unlimited Hierarchical Category Tree View structure.

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">

</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>Category List</h3>

                    <ul id="tree1">

                        @foreach($categories as $category)

                            <li>

                                {{ $category->title }}

                                @if(count($category->childs))

                                    @include('category.manageChild',['childs' => $category->childs])

                                @endif

                            </li>

                        @endforeach

                    </ul>

                </div>

                <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>
                        <select id="parent_id" name="parent_id" class="form-control">
                            <option value="0">Select</option>
                            @foreach($allCategories as $rows)
                                    <option value="{{ $rows->id }}">{{ $rows->title }}</option>
                            @endforeach
                        </select>

                        @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>

<script src="{{ asset('js/treeview.js') }}"></script>

</body>

</html>

manageChild.blade.php

<ul>

    @foreach($childs as $child)

        <li>

            {{ $child->title }}

            @if(count($child->childs))

                @include('category.manageChild',['childs' => $child->childs])

            @endif

        </li>

    @endforeach

</ul>

Create CSS and JS File

Now you have to add CSS file inside “public/css” and js file inside “public/js” accordingly.

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;

}

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); //li with children ul
            branch.prepend("<i class='indicator glyphicon " + closedClass + "'></i>");
            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();

$('#tree2').treed({openedClass:'glyphicon-folder-open', closedClass:'glyphicon-folder-close'});

$('#tree3').treed({openedClass:'glyphicon-chevron-right', closedClass:'glyphicon-chevron-down'});

You are almost done. Now you just want to run the site example as per my setup.

http://localhost/laravel-hierarchical-category/public/category-tree-view
Laravel Unlimited Hierarchical Category Tree View - Demo

Your Laravel Unlimited Hierarchical Category Tree View is ready to use. Below is the GitHub link for code structure.

9 thoughts on “Laravel Unlimited Hierarchical Category Tree View

  1. ahmed masry

    that is great tutorial but the last step when i add the jquery code it doesn’t work means doesn’t make expand and collapse why?

    Reply
  2. Steven Lenzen

    “Having read this I believed it was really informative. I appreciate you finding the time and effort to put this information together. I once again find myself personally spending a significant amount of time both reading and posting comments. But so what, it was still worthwhile!”

    Reply
  3. Destiny Monarca

    Saved as a favorite!, I enjoy your blog!

    Reply
  4. Magdalene Leibel

    First time visiting your website, I enjoy your blog!

    Reply
  5. Tien Huntsberger

    tҺe website іѕ really good, I enjoy your web site!

    Reply
  6. Devin Gronberg

    Saved as a favorite!, I really like your web site!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *