F
Filament4w ago
Amir

Repeater afterStateUpdated

In my Filament form, I have a Repeater that contains a Select field. Both the Repeater and the Select field have afterStateUpdated callbacks. When I make a selection in the Select field: The Repeater's afterStateUpdated is triggered first. Then, the Select field's afterStateUpdated is triggered. I want the Select field's afterStateUpdated to execute first, and then the Repeater's afterStateUpdated should execute.
4 Replies
LeandroFerreira
what is the goal?
Amir
AmirOP3w ago
Thank you for your reply.. I am developing an invoice application where I use a Filament Repeater to manage items. Within the Repeater, I have a Select field for choosing an item. Here's how it works: When an item is selected in the Select field, it automatically fetches the item's default price and sets the default quantity to 1. I calculate the total price dynamically based on the selected item's price and quantity. The issue arises when I manually adjust the item's price. While changing the item or quantity updates the total price correctly, modifying the price directly doesn't trigger an update to the total. Here's the code I am using:
Fieldset::make('items')->schema([
Repeater::make('invoiceProducts')
->relationship()
->schema([
Select::make('product_id')
->relationship('product', 'name')
->options(fn() => Product::where('store_id', Auth::user()->store_id)->pluck('name', 'id'))
->afterStateUpdated(function (?string $state, Forms\set $set, Forms\get $get) {
if ($state) {
$product = Product::find($state);
if ($product) {
$set('quantity', 1);
$set('price', $product->price);
$set('total', $product->price);
}
} else {
$set('price', null);
$set('quantity', 1);
$set('total', null);
}
self::updateTotals($get, $set);
}),
TextInput::make('price')
->afterStateUpdated(function (?string $state, Forms\set $set, Forms\get $get) {
$quantity = $get('quantity') ?? 1;
$set('total', $state * $quantity);
}),
TextInput::make('quantity')
->default(1)
->afterStateUpdated(function (?string $state, Forms\set $set, Forms\get $get) {
$price = $get('price') ?? 0;
$set('total', $price * $state);
}),
TextInput::make('total')
])
->live(onBlur: true)
->afterStateUpdated(function (Get $get, Set $set) {
self::updateTotals($get, $set);
})
]),
Fieldset::make('items')->schema([
Repeater::make('invoiceProducts')
->relationship()
->schema([
Select::make('product_id')
->relationship('product', 'name')
->options(fn() => Product::where('store_id', Auth::user()->store_id)->pluck('name', 'id'))
->afterStateUpdated(function (?string $state, Forms\set $set, Forms\get $get) {
if ($state) {
$product = Product::find($state);
if ($product) {
$set('quantity', 1);
$set('price', $product->price);
$set('total', $product->price);
}
} else {
$set('price', null);
$set('quantity', 1);
$set('total', null);
}
self::updateTotals($get, $set);
}),
TextInput::make('price')
->afterStateUpdated(function (?string $state, Forms\set $set, Forms\get $get) {
$quantity = $get('quantity') ?? 1;
$set('total', $state * $quantity);
}),
TextInput::make('quantity')
->default(1)
->afterStateUpdated(function (?string $state, Forms\set $set, Forms\get $get) {
$price = $get('price') ?? 0;
$set('total', $price * $state);
}),
TextInput::make('total')
])
->live(onBlur: true)
->afterStateUpdated(function (Get $get, Set $set) {
self::updateTotals($get, $set);
})
]),
`
public static function updateTotals(Get $get, Set $set): void
{
// Retrieve selected products and quantities
$selectedProducts = collect($get('invoiceProducts'))->filter(fn($item) => !empty($item['product_id']) && !empty($item['quantity']));

// Return early if no products are selected
if ($selectedProducts->isEmpty()) {
$set('subtotal', '0');
$set('total', '0');
return;
}

// Fetch prices for selected products
$prices = Product::find($selectedProducts->pluck('product_id'))->pluck('price', 'id');

// Calculate subtotal
$subtotal = $selectedProducts->reduce(function ($total, $item) use ($prices) {
return $total + ($item['price'] * $item['quantity']);
}, 0);

// Update calculated fields
$set('subtotal', $subtotal);
$set('total', $subtotal - $get('discount_amount'));
}
public static function updateTotals(Get $get, Set $set): void
{
// Retrieve selected products and quantities
$selectedProducts = collect($get('invoiceProducts'))->filter(fn($item) => !empty($item['product_id']) && !empty($item['quantity']));

// Return early if no products are selected
if ($selectedProducts->isEmpty()) {
$set('subtotal', '0');
$set('total', '0');
return;
}

// Fetch prices for selected products
$prices = Product::find($selectedProducts->pluck('product_id'))->pluck('price', 'id');

// Calculate subtotal
$subtotal = $selectedProducts->reduce(function ($total, $item) use ($prices) {
return $total + ($item['price'] * $item['quantity']);
}, 0);

// Update calculated fields
$set('subtotal', $subtotal);
$set('total', $subtotal - $get('discount_amount'));
}
`
LeandroFerreira
TextInput::make('price')
...
->live(onBlur: true)
TextInput::make('price')
...
->live(onBlur: true)
?
Amir
AmirOP3w ago
I have problem with select item in first time, I show that in uploaded file, It is about one month I searching for the reason, I will very appreciate if you can help me with this.
Want results from more Discord servers?
Add your server