use Alpine js for filament form input reactive using $wire.entangle

<?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());
    // }
}

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *