Using filters in listing
Craftable PRO does not generate listings with filters for now, so you have to edit generated files manually to add filters if you need to. You can follow this documentation page to learn how to add filters to your listing.
In this documentation I will use the Article
model as an example and I will implement filters for author_id
column which will allow to filter articles by their authors and published_at
column, which will allow to filter articles based on the day they are published at .
Edit your controller
First we need to edit generated controller for our model and add columns we want to filter by into the query builder using the allowedFilters
method. You can learn more about the query builder in the Spatie's Query Builder documentation (opens in a new tab).
I will also include all authors in the Inertia response so we can use them in the Multiselect component later. All together it will look like this:
public function index(IndexArticlesRequest $request)
{
$articlesQuery = QueryBuilder::for(Article::class)
->allowedFilters([
AllowedFilter::custom('search', new FuzzyFilter(
'id',
'title',
'published_at'
)),
AllowedFilter::exact('author_id'),
AllowedFilter::callback('published_at', fn (Builder $query, $value) => $query->whereDate('published_at', $value)),
])
->defaultSort('id')
->allowedSorts(['id', 'title', 'published_at'])
->with('author');
if ($request->wantsJson() && $request->get('bulk_select_all')) {
return response()->json($articlesQuery->select(['id'])->pluck('id'));
}
$articles = $articlesQuery
->select(['id', 'title', 'published_at', 'author_id'])
->paginate($request->get('per_page'))->withQueryString();
return Inertia::render('Article/Index', [
'articles' => $articles,
'authors' => Author::get()->map->only(['id', 'full_name']),
]);
}
You can define filters simply by passing the column name to the
allowedFilters
method, but in this case we want to use exact match for the
author_id
column and we want to use custom callback for the published_at
column so we can filter by date, without taking time into the account. You can
learn more about all the options in the Spatie's Query Builder
documentation (opens in a new tab).
Import useListingFilters hook
Next we need to edit generated Vue component for listing. In our case it is located in resources/js/craftable-pro/Pages/Article/Index.vue
.
To make things little bit easier, we created handy useListingFilters
hook that you can use to add filters to your listing. You can import it like this:
import { useListingFilters } from "craftable-pro/hooks/useListingFilters";
This hook has two parameters. First one is the URL of your Listing, in our case it is route("craftable-pro.articles.index")
. Second one is the default values for filters. In our case we want to filter by author_id
and published_at
columns. We can get the default values from the page props where filter
is predefined object to contain all filters. All together it will looke like this:
<template>...</template>
<script setup lang="ts">
import { useListingFilters } from "craftable-pro/hooks/useListingFilters";
...
const { filtersForm, resetFilters, activeFiltersCount } = useListingFilters(
route("craftable-pro.articles.index"),
{
author_id: usePage().props.filter?.author_id ?? null,
published_at: usePage().props.filter?.published_at ?? null,
}
);
</script>
filter
in usePage().props.filter
is default key in the page props that is
used to pass filters to the listing. You can change this key by customizing
the HandleInertiaMiddleware. See the InertiaJS configuration
page (opens in a new tab)
for more details.
Import FiltersDropdown component
Next we need to import FiltersDropdown
component that will be used to display filters in the listing. You can import it like this:
import { FiltersDropdown } from "craftable-pro/Components";
Afterward you have to use the slot in the component Listing
named #actions
to inject FiltersDropdown
component into your listing header. Don't forget to pass all the required props, namely activeFiltersCount
and resetFilters
. The whole Index.vue component should look something like this.
<template>
...
<PageContent>
<Listing
:baseUrl="route('craftable-pro.articles.index')"
:data="articles"
dataKey="articles"
>
<template #actions>
<FiltersDropdown
:activeFiltersCount="activeFiltersCount"
:resetFilters="resetFilters"
>
<Multiselect
v-model="filtersForm.author_id"
name="author_id"
:label="$t('craftable-pro', 'Authors')"
:options="authors"
optionsLabel="full_name"
optionsValueProp="id"
/>
<DatePicker
v-model="filtersForm.published_at"
name="published_at"
:label="$t('craftable-pro', 'Published at')"
/>
</FiltersDropdown>
</template>
...
</Listing>
</PageContent>
</template>
<script setup lang="ts">
import { useListingFilters } from "craftable-pro/hooks/useListingFilters";
import {
PageContent,
Listing,
Multiselect,
DatePicker,
FiltersDropdown,
} from "craftable-pro/Components";
...
const { filtersForm, resetFilters, activeFiltersCount } = useListingFilters(
route("craftable-pro.articles.index"),
{
author_id: usePage().props.filter?.author_id ?? null,
published_at: usePage().props.filter?.published_at ?? null,
}
);
</script>
Keep in mind that some parts of the code above were hidden for the sake of brevity.
Try it out
Now you can try it out. You should see the filters in the listing header. You can use them to filter articles by their authors and by the day they are published at. This is just a basic example, you can do so much more with filters. Also if you have any trouble getting them to work, feel free to contact us.