<?php
namespace App\Filament\Pages;
use Filament\Pages\Page;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\MarkdownEditor;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use App\Models\ContohAlpine as ContohAlpineModel;
class ContohAlpine extends Page implements HasForms
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-document-text';
protected static string $view = 'filament.pages.contoh-alpine';
public ?array $data = [];
public function mount(): void
{
$data = ContohAlpineModel::find(3);
$formData = $data->toArray();
// $total = 0;
// foreach ($formData['data_repeater'] as $k => $v) {
// $total += $v['price'] * $v['quantity'];
// }
// $formData['total'] = $total;
$this->form->fill($formData);
}
public function form(Form $form): Form
{
return $form
->schema([
\Filament\Forms\Components\Group::make()
->extraAttributes(function ($component) {
$statePath = $component->getStatePath();
return [
'x-data' => '{
total: $wire.entangle(\'' . $statePath . '.total\'),
updateTotal() {
this.total = Array.from(document.querySelectorAll(`[data-amount]`))
.reduce((sum, el) => {
const row = Alpine.$data(el);
return sum + (parseFloat(row.amount) || 0);
}, 0);
console.log("update");
}
}',
'x-init' => '$nextTick(() => {
updateTotal();
// Watch for repeater DOM changes
const repeater = document.querySelector("[data-repeater]");
const observer = new MutationObserver(() => {
console.log("row changes");
updateTotal();
});
if (repeater) {
observer.observe(repeater, { childList: true, subtree: true });
}
})',
'@row-updated.window' => 'updateTotal()',
'data-repeater' => true,
];
})
->schema([
\Filament\Forms\Components\Section::make('Invoice')
->schema([
\Filament\Forms\Components\Repeater::make('data_repeater')
// ->live()
->schema([
\Filament\Forms\Components\Group::make()
->extraAttributes(function ($component) {
$statePath = $component->getStatePath(); // data.data_repeater.X
// dd($statePath, $component->getState($statePath));
return [
'x-data' => "{
price: \$wire.entangle('{$statePath}.price'),
quantity: \$wire.entangle('{$statePath}.quantity'),
amount: \$wire.entangle('{$statePath}.amount'),
updateAmount() {
this.amount = (parseFloat(this.price) || 0) * (parseFloat(this.quantity) || 0);
\$dispatch('row-updated');
},
}",
];
})
->schema([
\Filament\Forms\Components\TextInput::make('price')
->numeric()
->live()
->required()
->extraAttributes([
'x-model' => 'price',
'@input' => 'updateAmount()',
]),
\Filament\Forms\Components\TextInput::make('quantity')
->numeric()
->live()
->required()
->extraAttributes([
'x-model' => 'quantity',
'@input' => 'updateAmount()',
]),
\Filament\Forms\Components\TextInput::make('amount')
->numeric()
->readonly()
->extraAttributes(function ($component) {
$statePath = $component->getStatePath();
return [
'x-model' => 'amount',
// 'x-effect' => "\$watch('amount', value => \$wire.set('{$statePath}', value))",
'data-amount' => true,
];
}),
])
->columns(3),
])
->columns(1),
\Filament\Forms\Components\TextInput::make('total')
->readonly()
->required()
->extraAttributes(function ($component) {
$statePath = $component->getStatePath();
return [
'x-model' => 'total',
// 'x-effect' => "\$watch('total', value => \$wire.set('{$statePath}', value))",
];
}),
])
->footerActions([
\Filament\Forms\Components\Actions\Action::make('submit')
->action(function ($component) {
$data = $this->form->getState();
$data = ContohAlpineModel::create([
'data_repeater' => $data['data_repeater'],
]);
dd($data);
}),
]),
])
->columnSpan('full'),
])
->statePath('data');
}
// public function create(): void
// {
// dd($this->form->getState());
// }
}
use Alpine js for filament form input reactive using $wire.entangle
by
Tags:
Leave a Reply