Filament Relation Manager: Live-Update Main Form After Changes

In Filament, you can attach/detach a relationship with the Relation Manager. But what if you want to refresh the main form after creating/editing/deleting a record in the Relation Manager? Let me show you how to do it.

In this example, we will have a Product Model with many Payment. After adding a new payment, the form will be refreshed to show the sum of payments.

update after relation manager create record


Laravel Project Structure

First, let's see what the relations in the Model and Filament Resource look like.

app/Models/Product.php:

use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
class Product extends Model
{
protected $fillable = [
'name',
];
 
public function payments(): BelongsToMany
{
return $this->belongsToMany(Payment::class);
}
 
public function totalPayments(): int
{
return $this->payments->sum('total');
}
}

The Payment Model only has two fields.

app/Models/Payment.php:

class Payment extends Model
{
protected $fillable = [
'plan_type',
'total',
];
}

Filament Resource Form

For the Filament Resource, the form for the product looks like this.

app/Filament/ProductResource.php:

use App\Models\Product;
use Filament\Forms;
use Filament\Forms\Form;
 
class ProductResource extends Resource
{
protected static ?string $model = Product::class;
 
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
 
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Group::make()
->schema([
Forms\Components\Section::make()
->schema([
Forms\Components\TextInput::make('name'),
]),
])
->columnSpan(['lg' => fn (?Product $record): int => $record ? 2 : 3]),
Forms\Components\Group::make()
->schema([
Forms\Components\Section::make()
->schema([
Forms\Components\Placeholder::make('created_at')
->label('Created at')
->content(fn (Product $record): ?string => $record->created_at?->diffForHumans()),
Forms\Components\Placeholder::make('payments_count')
->label('Total payments')
->content(fn (Product $record) => $record->totalPayments()),
]),
])
->columnSpan(['lg' => 1])
->hiddenOn('create')
])->columns(3);
}
 
// ...
}

This is what the edit page looks like. We will update the Total payments value.

edit product form


Filament Relation Manager

And lastly, we need a Relation Manager.

app/Filament/ProductResource/RelationManagers/PaymentsRelationManager.php:

class PaymentsRelationManager extends RelationManager
{
protected static string $relationship = 'payments';
 
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('plan_type')
->options([
'monthly' => 'Monthly',
'yearly' => 'Yearly',
])
->required(),
Forms\Components\TextInput::make('total')
->required()
->numeric(),
]);
}
 
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('plan_type')
->columns([
Tables\Columns\TextColumn::make('plan_type'),
Tables\Columns\TextColumn::make('total'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make(),
]);
}
}

We have two simple inputs for the create form in the relation manager.

relation manager form

Finally, the preparation phase is done.


Refreshing Update Form

This is where we get to the actual topic of this tutorial.

We need to refresh the edit form so that the total payments will get updated. To do this, we need to dispatch an event after the action in the relation manager and listen for it in the edit page.

app/Filament/ProductResource/RelationManagers/PaymentsRelationManager.php:

use Livewire\Component;
 
class PaymentsRelationManager extends RelationManager
{
// ...
 
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('plan_type')
->columns([
Tables\Columns\TextColumn::make('plan_type'),
Tables\Columns\TextColumn::make('total'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make()
->after(function (Component $livewire) {
$livewire->dispatch('refreshProducts');
}),
])
->actions([
Tables\Actions\EditAction::make()
->after(function (Component $livewire) {
$livewire->dispatch('refreshProducts');
}),
Tables\Actions\DeleteAction::make()
->after(function (Component $livewire) {
$livewire->dispatch('refreshProducts');
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()
->after(function (Component $livewire) {
$livewire->dispatch('refreshProducts');
}),
]),
])
->emptyStateActions([
Tables\Actions\CreateAction::make()
->after(function (Component $livewire) {
$livewire->dispatch('refreshProducts');
}),
]);
}
}

Here, we are using after lifecycle hook to fire a Livewire event after the action.

Next, we need to listen for the event and refresh the page.

app/Filament/ProductResource/Pages/EditProduct.php:

use Livewire\Attributes\On;
 
class EditProduct extends EditRecord
{
// ...
 
#[On('refreshProducts')]
public function refresh(): void
{
}
}

After creating a new payment, editing, or deleting the Total payments will be updated without page refresh.

update after relation manager create record


If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.

avatar

Thank you very much for this content. I was looking for this.

avatar

this is awesome 👍

avatar

not working on filament v2, anyone can help

avatar

livewire v2 has completely different syntax for events. check the docs for livewire v2 and adjust to your needs

avatar

thanks nerijus, just got this trick on youtube. it works like charms!

on parent edit page protected $listeners = ['refresh' => 'render'];

on relation managers page > create /edit /delete action $livewire->emit('refresh');

Like our articles?

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

Recent Premium Tutorials