Crash on getTableFilterState() on select filter with relationship

Hi! We are looking to prevent initial loading of the first x resources when opening a list resource page and came up with a solution like this:
protected function getTableQuery(): Builder
{
$this->countActiveFilters();
return parent::getTableQuery()
->when(
$this->filterCount == 0,
fn ($query) => $query->where(DB::raw('1 = 0')),
);

return parent::getTableQuery();
}
protected function getTableQuery(): Builder
{
$this->countActiveFilters();
return parent::getTableQuery()
->when(
$this->filterCount == 0,
fn ($query) => $query->where(DB::raw('1 = 0')),
);

return parent::getTableQuery();
}
Whereas the countActiveFilters() is as follows. This works fine when using a text input filter or a select filter with manual options. But when using a select filter based on a relationship the page crashes. Is there any way to improve this code? Thanks in advance!
private function countActiveFilters(): void
{
$this->filterCount = 0;
if (!isset($this->cachedTableFilters)) {
return;
}
foreach ($this->getTableFilters() as $filter) {
$filterContainer = $this->getTableFilterState($filter->getName()) ?? [];
$data = array_values($filterContainer);
$this->filterCount += count(array_filter($data));
}
}
private function countActiveFilters(): void
{
$this->filterCount = 0;
if (!isset($this->cachedTableFilters)) {
return;
}
foreach ($this->getTableFilters() as $filter) {
$filterContainer = $this->getTableFilterState($filter->getName()) ?? [];
$data = array_values($filterContainer);
$this->filterCount += count(array_filter($data));
}
}
10 Replies
TiBiBa
TiBiBaOP2y ago
I attempted to improve this code by using the $this->tableFilters value but this is always the amount of filters, not the amount of active ones. So this didn't work:
return parent::getTableQuery()
->when(
$this->tableFilters == null,
fn ($query) => $query->where(DB::raw('1 = 0')),
);
return parent::getTableQuery()
->when(
$this->tableFilters == null,
fn ($query) => $query->where(DB::raw('1 = 0')),
);
LeandroFerreira
You could try something like this:
protected function getTableQuery(): Builder
{
$filtered = Arr::where($this->tableFilters, function (array $value, string $key) {
return $value !== ['value' => null];
});

return parent::getTableQuery()
->when(
count($filtered) === 0,
fn (Builder $query) => $query->whereId(null)
);
}
protected function getTableQuery(): Builder
{
$filtered = Arr::where($this->tableFilters, function (array $value, string $key) {
return $value !== ['value' => null];
});

return parent::getTableQuery()
->when(
count($filtered) === 0,
fn (Builder $query) => $query->whereId(null)
);
}
TiBiBa
TiBiBaOP2y ago
Thanks for your reply! As I use custom filter forms the data is nested and will always return a count of the amount of attributes:
array:5 [▼
"id" => array:1 [▶
"id" => null
]
"username" => array:1 [▶
"username" => null
]
"first_name" => array:1 [▶
"first_name" => null
]
"last_name" => array:1 [▶
"last_name" => null
]
"email" => array:1 [▶
"email" => null
]
]
array:5 [▼
"id" => array:1 [▶
"id" => null
]
"username" => array:1 [▶
"username" => null
]
"first_name" => array:1 [▶
"first_name" => null
]
"last_name" => array:1 [▶
"last_name" => null
]
"email" => array:1 [▶
"email" => null
]
]
It seems the issue is the combination of custom form filters and a default selectFilter based on a relationship. The page crashed on trying to read the values. Might be because one is a nested value from the custom form and the other one is default? Still not sure on the exact cause (and solution...)
LeandroFerreira
Did you try to create a Select field in the form filter?
TiBiBa
TiBiBaOP2y ago
No the select if a default selectFilter, as described in the documentation. Like this:
SelectFilter::make('group')->searchable()
->relationship('group', 'name')
SelectFilter::make('group')->searchable()
->relationship('group', 'name')
The textual filters are using a custom form like this:
Filter::make('username')
->form([
TextInput::make('username')
])
->query(function (Builder $query, array $data): Builder {
return $query
->when(
$data['username'],
fn (Builder $query, $name): Builder => $query->where('username', 'LIKE', '%'.$name.'%'),
);
}),
Filter::make('username')
->form([
TextInput::make('username')
])
->query(function (Builder $query, array $data): Builder {
return $query
->when(
$data['username'],
fn (Builder $query, $name): Builder => $query->where('username', 'LIKE', '%'.$name.'%'),
);
}),
LeandroFerreira
Ok. I think you can keep selectFilter. What is the error on the browser?
TiBiBa
TiBiBaOP2y ago
Tha'ts the weird thing. The browser doesn't throw an error. It just keeps loading and returns a white page after a while
LeandroFerreira
Should work... Can you share the project on github?
Kenneth Sese
Kenneth Sese2y ago
Checking for a filter being active is complicated because of all the different ways filters can be active and, as I had mentioned in your previous help, can give false negatives depending on the filter type. You can try to check each filter against its default value to see if it’s active or not. The most reliable method I have found, which is weird, is to check against the indicator status. Filament does all the heavy lifting for us already to check against default values to display indicators so use that to determine if a filter is active or not. I use this in a slightly different context, but you can adapt to return a count() instead):
collect($livewire->getCachedTableFilters())
->mapWithKeys(fn (\Filament\Tables\Filters\BaseFilter $filter): array => [$filter->getName() => $filter->getIndicators()])
->filter(fn (array $indicators): bool => count($indicators))
->flatten();
collect($livewire->getCachedTableFilters())
->mapWithKeys(fn (\Filament\Tables\Filters\BaseFilter $filter): array => [$filter->getName() => $filter->getIndicators()])
->filter(fn (array $indicators): bool => count($indicators))
->flatten();
This might not work if you have a filter turned on by default (ie, you see a filter indicator when you load the page), but if I’m understanding your question correctly, no filters are turned on by default so this should work. BTW, this is how filament determines whether or not the little filter indicator dot should be displayed.
TiBiBa
TiBiBaOP2y ago
Unfortunately the code snippet crashes on the getIndicators() function when being called on the select filter with relationship. Resulting in the same white page issue as before
Want results from more Discord servers?
Add your server