Search code examples
phplaravellaravel-livewire

Laravel Livewire Multiple Category Filter not Working


I am trying to make simple filtering with livewire in laravel but got stuck on the multiple category filters.

// Filters
public $filter = [
    "title" => "",
    "rangeFrom" => "",
    "rangeTo" => "",
    "order_field" => "order_by_name_asc",
    "selectedCat" => [],
];
// method of query
else if(!empty($this->filter['selectedCat'])) {
        $categories = explode(',', $this->filter['selectedCat']);

        $products = Product::where('category_id',
                    function ($query) use ($categories) {
                                $query->whereIn('category_id', $categories);
                            })->limit($this->loadAmount)
                                ->get();
    }
// html[![enter image description here][1]][1]
<p class="mt-4">Catgegories</p>
    @foreach ($categories as $cat)
    <div class="flex" wire:key="{{ $cat->id }}">
        <input type="checkbox" id="{{ $cat->title }}"
                class="h-4 w-4 text-gray-700 border rounded mr-2"
                wire:model="filter.selectedCat"
                value="{{ $cat->id }}">
        <label for="{{ $cat->title }}">{{ $cat->title }}</label>
    </div>
    @endforeach

The final result in the picture below... enter image description here


Solution

  • What you're after can be achieved by binding to a dynamic element in your selectedCat nested array.

    wire:model="filter.selectedCat.{{ $cat->id }}"
    

    What this does is add an element to your array where the key is the id of the category and value is true, or false once it is unselected. The array keys can then be used to determine which categories to filter on, just need to remove the elements with a false value.

    Blade file

    <div>
        @foreach ($this->categories as $category)
            <div class="flex items-center space-x-4 mb-2" wire:key="{{ $category->id }}">
                <input type="checkbox" id="{{ $category->title }}" name="{{ $category->title }}"
                    wire:model="filters.categories.{{ $category->id }}" />
                <label for="{{ $category->title }}">{{ $category->title }}</label>
            </div>
        @endforeach
    
        <div class="grid grid-cols-4 gap-4">
            @foreach ($this->results as $result)
                <div>{{ $result->title }} ({{ $result->category->title }})</div>
            @endforeach
        </div>
    </div>
    

    Component

    public $filters = [
        'categories' => [],
    ];
    
    public function getCategoriesProperty()
    {
        return Category::all();
    }
    
    public function getResultsProperty()
    {
        if (empty($this->filters['categories'])) {
            return Product::all();
        }
    
        // this is where we remove the categories with a false value
        $this->filters['categories'] = array_filter($this->filters['categories']);
    
        return Product::whereIn('category_id', array_keys($this->filters['categories']))->get();
    }
    
    public function render()
    {
        return view('livewire.category-filter');
    }