Filament: Edit Only Single Record with Custom Page

Filament is great for creating full CRUDs in Resources. But what if you want to create just a single Edit form for one specific record, without the full Resource? Let's use a Custom Page for it.

In this example, we will use a company that belongs to a user.

The idea comes from the question on the official Filament Discord:

Here's the result of what we're gonna be building.

edit company page


Prepare Custom Page

The main thing you need to understand that it's sometimes easier to create a Custom Page with just the actions you want than to create a full Filament Resource and then try to "strip it down".

Also, Filament comes with separated packages, so you can use Filament Forms/Tables even outside of Filament, in Livewire components.

So first, create a custom page and prepare it to use Filament Forms.

php artisan make:filament-page EditCompany --type=custom

Notice: when creating a custom page, don't specify any associated Resource.

Now, we need to implement an interface and add a trait to use Filament forms.

app/Filament/Pages/EditCompany.php:

use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Concerns\InteractsWithForms;
 
class EditCompany extends Page implements HasForms
{
use InteractsWithForms;
}

Custom page now can use Filament Forms, so let's add a form.

app/Filament/Pages/EditCompany.php:

use Filament\Forms\Form;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Concerns\InteractsWithForms;
 
class EditCompany extends Page implements HasForms
{
use InteractsWithForms;
 
public ?array $data = [];
 
protected static ?string $navigationIcon = 'heroicon-o-document-text';
 
protected static string $view = 'filament.pages.edit-company';
 
public function mount(): void
{
$this->form->fill();
}
 
public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),
])
->statePath('data');
}
}

And we need to render the form in the Blade file.

resources/views/filament/pages/edit-company.blade.php:

<x-filament-panels::page>
<x-filament-panels::form>
{{ $this->form }}
</x-filament-panels::form>
</x-filament-panels::page>

After visiting the edit company page, we now see an empty form.

empty edit company form


Filling and Submitting Form

We must fill form inputs with the company information first. Because here we have a hasOne relation to the company, we get all the company data by just doing auth()->user()->company.

app/Models/User.php:

use Illuminate\Database\Eloquent\Relations\HasOne;
 
class User extends Authenticatable implements FilamentUser
{
// ...
 
public function company(): HasOne
{
return $this->hasOne(Company::class);
}
}

app/Filament/Pages/EditCompany.php:

class EditCompany extends Page implements HasForms
{
// ...
 
public function mount(): void
{
$this->form->fill();
$this->form->fill(auth()->user()->company->attributesToArray());
}
 
// ...
}

Next, we need a submit button.

app/Filament/Pages/EditCompany.php:

use Filament\Actions\Action;
 
class EditCompany extends Page implements HasForms
{
// ...
 
protected function getFormActions(): array
{
return [
Action::make('save')
->label(__('filament-panels::resources/pages/edit-record.form.actions.save.label'))
->submit('save'),
];
}
}

resources/views/filament/pages/edit-company.blade.php:

<x-filament-panels::page>
<x-filament-panels::form>
{{ $this->form }}
 
<x-filament-panels::form.actions
:actions="$this->getFormActions()"
/>
</x-filament-panels::form>
</x-filament-panels::page>

After revisiting the edit company page, we can see the form is filled with data, and we have a submit button.

edit company page

All that's left is to update the data. We need a method for updating the company and to add wire:submit directive to the form.

resources/views/filament/pages/edit-company.blade.php:

<x-filament-panels::page>
<x-filament-panels::form>
<x-filament-panels::form wire:submit="save">
{{ $this->form }}
 
<x-filament-panels::form.actions
:actions="$this->getFormActions()"
/>
</x-filament-panels::form>
</x-filament-panels::page>

app/Filament/Pages/EditCompany.php:

use Filament\Support\Exceptions\Halt;
 
class EditCompany extends Page implements HasForms
{
// ...
 
public function save(): void
{
try {
$data = $this->form->getState();
 
auth()->user()->company->update($data);
} catch (Halt $exception) {
return;
}
}
 
// ...
}

Lastly, let's send a success notification message after updating company information.

use Filament\Notifications\Notification;
 
class EditCompany extends Page implements HasForms
{
// ...
 
public function save(): void
{
try {
$data = $this->form->getState();
 
auth()->user()->company->update($data);
} catch (Halt $exception) {
return;
}
 
Notification::make()
->success()
->title(__('filament-panels::resources/pages/edit-record.notifications.saved.title'))
->send();
}
 
// ...
}

notification message

avatar

Can show an example of how to add a custom Clear button with notification? i.e. After clicking on Clear button, it can clear/reset some fields of this record and show a notification that this record was Cleared

avatar

Just make an action button where action would be to set fields to initial value and send the notification

avatar

I could not get things to work, that's why I asked for an example.

avatar
Jahidul Islam (Shojib Flamon)

It was an excellent elaboration that might help build any predefined settings page like Site title, Notification Email, Enable/Disable any feature, Some footer link, or many more things.

One thing I would like to address, HasForms interface is an unnecessary implementation. It is already announced in Filament\Pages\Page. So we might remove it as I Think.

Thanks

avatar

Kinda. But for settings you should use official plugin for spatie laravel settings package

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 50 courses (910 lessons, total 46 h 42 min)
  • 69 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials