Nova Customisable Resource Fields
This week I'm back working on Laravel Nova, which includes working my way through the nova-issues repo and seeing what's what.
One issue that caught my eye was a feature request from @Grayda, https://github.com/laravel/nova-issues/issues/2622. They asked that we provide functionality in Nova that allows users to show or hide fields based on their selection.
I immediately had a feeling this may be possible using the Filters feature of Nova, so I gave it a quick go and it worked!
The Code
First thing's first, we start by creating a boolean filter:
php artisan nova:filter FieldsFilter --boolean
We use a boolean filter here so that we can display checkboxes to the user:
Now that we have our filter, we can start implementing the logic that we need. Within the options
method, we define the array of fields that we want the user to be able to toggle:
/**
* Get the filter's available options.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function options(Request $request)
{
return [
'Name' => 'name',
'Gravatar' => 'gravatar',
'Email' => 'email',
];
}
Note that with this method the options array uses a
value/key
syntax.
If we want to enable these fields by default, we'll also need to override the default
method. You can do this by adding this code to your filter:
/**
* Set the default options for the filter.
*
* @return array
*/
public function default()
{
return [
'name' => true,
'gravatar' => true,
'email' => true,
];
}
Once we've decided which fields the user should be allowed to toggle, we need to add the filter to our Resource. In the examples I've used above, we're modifying the User
resource:
use App\Nova\Filters\FieldsFilter;
/**
* Get the filters available for the resource.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function filters(Request $request)
{
return [
new FieldsFilter,
];
}
We're almost there, stay with me!
All we need to do now is toggle the field if the user wants to display it. Usually we'd use the fields
method to describe the fields that you wish to display to a user. Since we only want to allow users to customise which fields are displayed on the index listing, we can use the fieldsForIndex
method instead. This is a two part change. Firstly, we need to store the FieldsFilter
in a variable so we can access it later:
/**
* Get the fields displayed by the resource index.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function fieldsForIndex(Request $request)
{
$fieldFilter = $request->filters()->first(function ($filter) {
return $filter->filter instanceof FieldsFilter;
});
return [
// Existing fields...
];
}
And finally, we need to modify our fields so that we hide it if the user no longer wants to see it:
return [
ID::make()->sortable(),
Gravatar::make('Gravatar')
->showOnIndex(Arr::get($fieldFilter->value, 'gravatar', true)),
Text::make('Name')
->showOnIndex(Arr::get($fieldFilter->value, 'name', true)),
Text::make('Email')
->sortable()
->showOnIndex(Arr::get($fieldFilter->value, 'email', true)),
];
Notice above how our fields don't contain any
rules
orhelp
calls? This is because the index listing doesn't need to know any of that! We can make this method a lot cleaner than the usualfields
method.
And we're done! Your users can now select which fields they want to display. You could take this further and have fields which are hidden by default, but then allow users to display them.
As a side note, you should be aware that each change will result in a fresh network request. This is required by Nova as changes to filters may result in a callback being handled differently, as demonstrated above with the use of $request->filters
.