Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

robcollier's avatar

Livewire checkbox filters - checkboxes disappearing

I'm building a full page Livewire component that filters Meilisearch results.

When I check one of the filters the remaning checkboxes disappear, and I am struggling to understand why. I followed a tutorial to figure out how to build the bulk of the component and in the tutorial the behaviour didn't occur. I've deconstructed the component to the bare minimum and the behaviour happens as soon as I wire up the checkboxes.

Here is the component :

 <?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\CourseDate;
use App\Models\Course;

class CourseBrowser extends Component
{

    public $queryFilters = [];

    public $priceRange = [
        'min' => null,
        'max' => null
    ];

    public function mount()
    {
        $this->queryFilters = [
            'venue' => [],
            'type' => [],
            'category' => [],
            'days'  => [],
            'supplier' => []
        ];
    }

    public function render()
    {

        $search = CourseDate::search(
            '',
            function ($meilisearch, string $query, array $options) {

                $filters = collect($this->queryFilters)
                    ->filter(fn ($filter) => !empty($filter))
                    ->recursive()
                    ->map(function ($value, $key) {
                        return $value->map(fn ($value) => $key . ' = "' . $value . '"');
                    })
                    ->flatten()
                    ->join(' AND ');

                $options['facets'] = ['venue', 'category', 'type', 'supplier', 'days'];
                $options['filter'] = null;

                if ($filters) {
                    $options['filter'] = $filters;
                }

                if ($this->priceRange['max']) {
                    $options['filter'] .= (isset($options['filter']) ? ' AND ' : '') . 'price <= ' . $this->priceRange['max'];
                }

                return $meilisearch->search($query, $options);
            }
        )->raw();

        $coursedates = CourseDate::find(collect($search['hits'])->pluck('id'));

        $minPrice = Course::all()->min('price');
        $maxPrice = Course::all()->max('price');

        $this->priceRange['min'] = $this->priceRange['min'] ?: $minPrice;
        $this->priceRange['max'] = $this->priceRange['max'] ?: $maxPrice;

        return view('livewire.course-browser')
            ->with(
                [
                    'coursedates' => $coursedates,
                    'filters' => $search['facetDistribution'],
                    'minPrice' => $minPrice,
                    'maxPrice' => $maxPrice,
                ]
            );
    }
}

and the blade view is thus:

(I've ommited everyhing outside of the wired up checkboxes and styling for brevity - by all means I can share the whole thing if neccesary


 <input type="checkbox" wire:model="queryFilters.{{ $title }}"
                             id="{{ $title }}_{{ strtolower($option) }}"
                             value="{{ $option }}">

Here is a gif of what happens:

https://imgur.com/a/7eEsY5E

Thanks in advance

0 likes
3 replies
robcollier's avatar

I crossposted this on Stackoverflow, and received a suggestion that this is one of many bugs in Livewire, and to wrap the checkboxes in a div and apply wire:ignore-self to it:

<div class="" wire:ignore.self>
......
</div>

This hasn't worked, however.

I just thought i'd add it here for posterity.

robcollier's avatar

After some perusal of the Meilisearch docs:

facetDistribution contains an object for every given facet. For each of these facets, there is another object containing all the different values and the count of matching documents. Note that zero values will not be returned: if there are no romance movies matching the query, romance is not displayed.

That suggests that the behaviour is normal 😳

On updating the search results, the facetDistribution array is updated with the filters belonging to the results that have been returned, and doesn't retain the ones with a zero value.

Before filtering:

 "facetDistribution":{
      "category":{
         "Hair":8
      },
      "days":{
         "1":4,
         "2":4
      },
      "supplier":{
         "Matrix":8
      },
      "type":{
         "In Person":8
      },
      "venue":{
         "Colchester":2,
         "Ipswich":1,
         "Norwich":1,
         "Peterborough":1,
         "Romford":3
      }
   },

After filtering:

 "facetDistribution":{
      "category":{
         "Hair":2
      },
      "days":{
         "1":1,
         "2":1
      },
      "supplier":{
         "Matrix":2
      },
      "type":{
         "In Person":2
      },
      "venue":{
         "Colchester":2
      }
   },

To be honest, I'd expected to retain the filters with a value of zero so I could re-filter and find courses that were present in Colchester OR Norwich, for example. In fact the tutorial I learned the process from appeared to show this behaviour.

I'm going to rewatch it again in case I misunderstood something!

Or perhaps the older version of Meilisearch being used in the tutorial allowed this?

Please or to participate in this conversation.