Only until Jan 16th: coupon RESOLUTION25 for 40% off Yearly/Lifetime membership!

Read more here

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');

avatar

Doesn't work with costum extraModalFooterActions

avatar

What doesn't work?

avatar

I am developing a project using Laravel with the Filament package. I have already created a form called "Area," which includes tables for State, LGA, Zone, Enumeration Area, and Code. Current Task: I now need to create a new form called "Street Enumeration." This form should include dependent select fields that allow users to choose: State LGA Zone Enumeration Area Code These selections should be populated based on existing records from the "Area" table. Additional Fields: In addition to the dependent selects, the form should also include the following fields: Street Name Entry Point (with longitude and latitude) Exit Point (with longitude and latitude) Street Description Request for Guidance: Could you provide guidance on how to implement this dependent select functionality and the additional fields in the "Street Enumeration" form? Thank you!

avatar

For the dependant there is a docs section how to do it.

Like our articles?

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

Recent New Courses