Skip to content
Advertisement

How to print infinity nested categories in dropdown (select) menu in Laravel

I have this category table:

id name parent_id
1 Programming 0
2 History 0
3 PHP 1
4 Javascript 1
6 World history 2
7 jQuery 4
8 AJAX 4
9 Europe 6
10 American 6
16 ajax nested 8

Here is how I get categories in controller:

$categories = Category::where('parent_id', '=', 0)->with('childs')->get();

And Model Category:

class Category extends Model
{
    use HasFactory;

    protected $fillable = ['name'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function posts()
    {
        return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
    }

    public function childs()
    {
        return $this->hasMany(Category::class, 'parent_id', 'id');
    }
}

I want to output categories, like this:

<select>
<option id="1">Programming</option>
<option id="3">Programming -> PHP</option>
<option id="4">Programming -> Javascript</option>
<option id="7">Programming -> Javascript -> jQuery</option>
<option id="8">Programming -> Javascript -> AJAX</option>
<option id="16">Programming -> Javascript -> AJAX -> ajax nested</option>
<option id="2">History</option>
<option id="6">History -> World history</option>
<option id="9">History -> World history -> Europe</option>
<option id="10">History -> World history -> American</option>
</select>

Which looks like: this

I am considering two options:

  1. Some service and clean php code with recursive function, which to return variable with complete HTML structure (select + options) and display that variable in template file.

  2. Some Laravel way, which I don’t know how to achieve.

Advertisement

Answer

In your main blade template do like below. Here we first add the select box then loop through the categories. If a parent category has childs, then first the childs are added by calling another template and passing childs data to it.

<select name="" id="">     
    @foreach ($categories as $category)
        <option value="{{ $category->id }}">{{ $category->name }}</option>

        @if (count($category->childs) > 0)
            @include('subcategories', ['subcategories' => $category->childs, 'parent' => $category->name])
        @endif

    @endforeach
</select>

Now, we have to create childs displaying template. Based on my example, the name should be subcategories.blade.php. In the child blade template, add the followings:

@foreach ($subcategories as $sub)
    <option value="{{ $sub->id }}">{{ $parent}} -> {{ $sub->name }}</option>

    @if (count($sub->childs) > 0)
        @php
            // Creating parents list separated by ->.
            $parents = $parent . '->' . $sub->name;
        @endphp
        @include('subcategories', ['subcategories' => $sub->childs, 'parent' => $parents])
    @endif
@endforeach

In the child template, we are recursively calling the child template itself over and over as long as each child has other childs.

And, here is the outcome on my machine: https://ibb.co/ynRB04h

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement