Hello i am facing an issue in filament v3.I am making an order form using repeater in which there is relation with product table. The thing i want to do is by selecting product in select the other fields that i created outside the repeater should update accordingly.So I am using afterStateUpdated on repeater. I changes the fields inside the repeater but the fields in the other section outside the repeater are not updating. heres the code:
Repeater::make('products')
->relationship()
->schema([
Select::make('product_id')
->label("Products")
->relationship('product','name')
->options(
$products->mapWithKeys(function (Product $product) {
return [$product->id => sprintf('%s ($%s)', $product->name, $product->price)];
})
)
->disableOptionWhen(function ($value, $state, Get $get) {
return collect($get('../*.product_id'))
->reject(fn($id) => $id == $state)
->filter()
->contains($value);
})
->required()
->createOptionForm([
FormsComponentsFileUpload::make('image')
->image()
->required(),
FormsComponentsTextInput::make('name')
->required()
->maxLength(255),
FormsComponentsRichEditor::make('description')
->required()
->maxLength(65535)
->columnSpanFull(),
FormsComponentsTextInput::make('sku')
->label('SKU')
->required()
->maxLength(255),
FormsComponentsTextInput::make('price')
->required()
->maxLength(255)
->numeric(),
FormsComponentsTextInput::make('qty')
->required()
->maxLength(255)
->numeric(),
FormsComponentsSelect::make('availablity')
->options([
"yes" => "Yes",
'no' => "No"
])
->required(),
FormsComponentsSelect::make('brands')
->relationship('brands', 'name')
->required()
->multiple()
->preload()
->createOptionForm([
FormsComponentsTextInput::make('name')
->required()
->maxLength(255),
FormsComponentsToggle::make('active')
->required(),
]),
FormsComponentsSelect::make('categories')
->relationship('categories', 'name')
->required()
->multiple()
->preload()
->createOptionForm([
FormsComponentsTextInput::make('name')
->required()
->maxLength(255),
FormsComponentsTextInput::make('description')
->required()
->maxLength(255),
FormsComponentsToggle::make('active')
->required(),
]),
FormsComponentsSelect::make('warehouse_id')
->relationship('warehouse', 'name')
->required()
->createOptionForm([
FormsComponentsTextInput::make('name')
->required()
->maxLength(255),
Toggle::make('active')
])
])
// ->reactive()
// ->afterStateUpdated(function ($state, callable $set) {
// $product = Product::find($state);
// if ($product) {
// $set('product_id', $state);
// $set('price', $product->price);
// }
// })
->columnSpan([
"md" => 5
]),
TextInput::make('amount')
->numeric()
->required()
->reactive()
->label('Quantity')
// ->afterStateUpdated(function ($state, callable $set, Get $get) {
// $product = Product::find($get('product_id'));
// if(isset($product->price)){
// $set('price', $product->price *$state);
// }
// })
->default(1)
->columnSpan([
"md" => 3
]),
TextInput::make('price')
->disabled()
->numeric()
->minValue('1')
->required()
->default(1)
->dehydrated()
->columnSpan([
"md" => 2
]),
])->columns(["md" => 10])
->live()
// After adding a new row, we need to update the totals
->afterStateUpdated(fn ($state) => dd($state))
// After deleting a row, we need to update the totals
->deleteAction(
fn(Action $action) => $action->after(fn(Get $get, Set $set) => self::updateTotals($get, $set)),
)
// Disable reordering
->reorderable(false)
])->collapsible(),
the other section code is here:
Section::make()
->columns(1)
->maxWidth('1/2')->schema([
TextInput::make('subtotal')
->numeric()
->readOnly()
->afterStateHydrated(function (Get $get, Set $set) {
self::updateTotals($get, $set);
}),
// TextInput::make('taxes')->required()->numeric()->default()
TextInput::make('total')->readOnly()->numeric()
])
and the function updateTotals is here:
public static function updateTotals(Get $get, Set $set): void
{
// Retrieve all selected products and remove empty rows
$selectedProducts = collect($get(‘products’))->filter(fn($item) => !empty($item[‘product_id’]) && !empty($item[‘amount’]));
// Retrieve prices for all selected products
$prices = Product::find($selectedProducts->pluck('product_id'))->pluck('price', 'id');
// Calculate subtotal based on the selected products and quantities
$subtotal = $selectedProducts->reduce(function ($subtotal, $product) use ($prices) {
return $subtotal + ($prices[$product['product_id']] * $product['amount']);
}, 0);
// Update the state with the new values
$set('subtotal', number_format($subtotal, 2, '.', ''));
$set('total', number_format($subtotal + ($subtotal * ($get('taxes') / 100)), 2, '.', ''));
}
i have taken this code from laravel Daily heres the link:code picked from here
2
Answers
Instead of using stateUpdate On repeater i have used placeholder and inside placeholder i am getting repeater fields and achieving the required results as follow
On your Repeater you have:
Is it the problem?