I struggled for a while trying to build a dependent select filter, trying to do it as two separate filters. Turns out the trick is to build it as a single form based filter, with both selects in the custom form.
In my app, we have a FlightLegs table, which pilots use to log flight hours for missions flown in an aircraft for a given day. FlightLegs belong to a DailyLog table, which stores the overall mission/aircraft details - aircraft, flight date, crew members, etc. Aircraft belong to Vendors (contracted aircraft operators). So from the FlightLegs table, the relationship to Aircraft is dailyLog.aircraft, and aircraft belongsTo Vendor.
I needed a pair of filters on the FlightLeg table, filtering for the Vendor and Aircraft, with Aircraft being dependent on Vendor - so if a vendor is selected, only show the aircraft for that vendor, and when a Vendor is selected, clear any current Aircraft selection if it doesn't belong to the selected Vendor.
// filter name can be anything you wantSelectFilter::make('aircraft') ->label('Aircraft') // build the filter form ->form([ // build the Vendor dropdown Select::make('vendor_id') ->label('Vendor') // select all Vendors ->options( fn() => Vendor::all()->pluck('name', 'id')->toArray() ) // when state updated, check to see if the currently selected aircraft belongs to the selected vendor ... ->afterStateUpdated(function ($state, callable $get, callable $set) { $vendor = Vendor::find($state); if ($vendor) { $aircraftId = (int) $get('aircraft_id'); if ($aircraftId && $aircraft = Aircraft::find($aircraftId)) { if ($aircraft->vendor_id !== $vendor->id) { // aircraft doesn't belong to vendor, so unselect it $set('aircraft_id', null); } } } }) // make the vendor dropdown reactive so we can rebuild the aircraft dropdown when state changes ->reactive(), // build the Aircraft dropdown Select::make('aircraft_id') ->label('Aircraft') // build the options ->options(function (callable $get, callable $set) { $vendor = Vendor::find($get('vendor_id')); // if a vendor is selected, just fetch the aircraft for this vendor thru the vendor's belongsTo aircraft if ($vendor) { return $vendor->aircraft->pluck('n_number', 'id'); } // no vendor selected, so get all aircraft return Aircraft::all()->pluck('n_number', 'id'); }), ]) // handle the query ->query(function (Builder $query, array $data) { // get the vendor and aircraft id's from the form's $data array $aircraftId = (int) $data['aircraft_id']; $vendorId = (int) $data['vendor_id']; // if an aircraft selected, scope the query to just that aircraft id with a nested whereHas if (!empty($aircraftId)) { $query->whereHas( 'dailyLog', fn(Builder $query) => $query->whereHas( 'aircraft', fn(Builder $query) => $query->where('id', '=', $aircraftId) ) ); } // if a vendor selected, scope the query to just aircraft with that vendor id with a nested whereHas if (!empty($vendorId)) { $query->whereHas( 'dailyLog', fn(Builder $query) => $query->whereHas( 'aircraft', fn(Builder $query) => $query->where('vendor_id', '=', $vendorId) ) ); } }),
Thank, it works fine.
however the counter of used filters remains at 0.
screenshot: https://ibb.co/LCk74Vq
ok, i found a solution https://filamentphp.com/docs/2.x/tables/filters#custom-indicators