Applying Filter using BelongsToMany Relationship in Livewire

In this Tutorial, we will see how to Filter Records using a BelongsToMany Relationship in Livewire. This is the part 6 of the Series related to adding New Functionality to a Table using Livewire. In Last Part of the Series we implemented Filter on the BelongsTo column of the Product Model using Livewire.

Lets say our Product Model has belongsToMany Relationship with Category as follows

    public function categories()
    {
        return $this->belongsToMany(Category::class);
    }

That means there is a Category Table which holds all the Categories. And then there is a Pivot Table which links Products and Categories. And we want to Filter using Category, so when the User selects a Category we will display only those Products which are related to that Category.

First of all we will fetch all the Categories. We would create a categories property and populate it in the mount method.

$this->categories = Category::pluck('name', 'id')->toArray();

And in the View, we would create the dropdown by looping through these categories.

<div>
    <label>
        Categories
    </label>
    <select>
        <option value="">Any</option>
        @foreach($categories as $category_id => $category_name)
        <option value="{{$category_id}}">{{$category_name}}</option>
        @endforeach
    </select>
</div>

The Dropdown will have all the Categories that User can select from. As usual we also have an Any option so as to display all the Products.

Next we will create a property called $selectedCategory and link it with above dropdown using wire:model.

<select wire:model="selectedCategory">
    <option value="">Any</option>
    @foreach($categories as $category_id => $category_name)
    <option value="{{$category_id}}">{{$category_name}}</option>
    @endforeach
</select>

This way whenever User changes the above Dropdown, the property $selectedCategory would be updated in the Component and Livewire will re-render the component. Now all we need to do is to change the Query to reflect the value of Selected Category.

Below is the current Query that we have.

public function query()
{
    return Product::query()
        ->when($this->selectedStatus, function($query) {
            return $query->where('status', $this->selectedStatus);
        })
        ->when($this->selectedBrand, function($query) {
            return $query->where('brand_id', $this->selectedBrand);
        });
}

We will include another when Condition and we would filter the records using whereHas Clause like below:

->when($this->selectedCategory, function($query) {
    return $query->whereHas('categories', function($query) {
        return $query->where('categories.id', $this->selectedCategory);
    });
});

Go ahead and test it, our Filter should be working now. So unlike the previous Filters where we were able to apply the Query directly on the Product Model, here we had to pass a Closure to whereHas in order to Filter using `BelongsToMany Relation.

If you have liked this Tutorial, please checkout the Livewire Package tall-crud-generator which automatically generates all the Code related to applying Filter on a BelongsToMany Relation.

Leave a Reply

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