How to access form state in Custom Livewire component

I have a form with: public function form(Form $form): Form { return $form ->schema([ TextInput::make('title')->live(), TextInput::make('slug')->live(), RichEditor::make('content')->live(), Livewire::make(MyDynamicComponent::class, ['bar' => 'baz']); ]); } but MyDynamicComponent need access to the form state as it need to render infos based on the latest form fields (preview). the Livewire::getData() is only called one time during initialization and updated values are not passed to the component
7 Replies
Dennis Koch
Dennis Koch2w ago
Do you absolutely need a Livewire component? Reactivity in Livewire is not that elaborate and in combination with Filament probably worse.
hitech95
hitech95OP2w ago
How would you do this? I need to render a preview of some data. It is a ChartJS. (basically I have a lot of repeaters with many data on it) I'm using a Filament Widget wrapped into a Livewire component. The only way I've found to properly is to use the ->key(fn() => uniqid()) so that the component is detroied and re-rendered each time. I'm open to any other alternative solution if there are better way to do so. Unfortunately boss is a PITA. And decided to use filament fore more than crud input.
Dennis Koch
Dennis Koch2w ago
Then you can just use a ViewField which can access the form data or the record via $getRecord() Filament Widgets are already Livewire components. So you wrap a LW component into another one
The only way I've found to properly is to use the ->key(fn() => uniqid()) so that the component is detroied and re-rendered each time.
So, it's working? 🤔 You could get the current record from the page/url. But the form data is more complex and probably needs to be passed around via Livewire events
hitech95
hitech95OP2w ago
MyDynamicComponent extends FilamentChat widget. So I'm only wrapping it once. It is working for now but we are planning to move to v4 in the future and we have created a lot of edge cases where we pushed filament to the limit. And this is one of the cases. so I wanted to know if there is a better way. I cannot use $record as the data must change real time. is it must depend of $livewire->state array.
Dennis Koch
Dennis Koch2w ago
Why do you need the form state for the chat? And that works with your approach? 🤔
hitech95
hitech95OP2w ago
LEt me give you the full-ish example The chart component:
CurveChart extends ChartWidget {

// All the passed fields for getData()
$title;
// ...
$minX;
$maxX;

// Some overrides
public function getHeading() {
return $this->title;
}

public function getType() {
return 'scatter';
}

// This build the data for the chart based on passed status
public function getData() {
// ...
}
}
CurveChart extends ChartWidget {

// All the passed fields for getData()
$title;
// ...
$minX;
$maxX;

// Some overrides
public function getHeading() {
return $this->title;
}

public function getType() {
return 'scatter';
}

// This build the data for the chart based on passed status
public function getData() {
// ...
}
}
TextInput::make('absolute_min_value_x')
->live()
->numeric()
->required(),
TextInput::make('absolute_max_value_x')
->live()
->numeric()
->required(),

// ... More fields for chart

Select::make('unit_measure_id')
->options([]), // List of key->value of StorageCurveUnitEnum

Livewire::make(CurveChart::class, function (Get $get) use ($graphType) {
return [
'title' => Lang::get(''),
'xLabel' => Lang::get(''),
'yLabel' =>Lang::get(''),
'is_relative' => $get('unit_measure_id') == StorageCurveUnitEnum::RELATIVE->getProp('old_code'),
'series' => [
'serieA' => [
'maxX' => $get('serieA.max_value_x'),
'maxY' => $get('serieA.max_value_y'),
'points' => $get('serieA.points')
],
// ...
'serieC' => [
'maxX' => $get('serieC.max_value_x'),
'maxY' => $get('serieC.max_value_y'),
'points' => $get('serieC.points'),
]
],
'minX' => $get('absolute_min_value_x'),
'maxX' => $get('absolute_max_value_x'),
'minY' => $get('absolute_min_value_y'),
'maxY' => $get('absolute_max_value_y'),
];
})->key(fn() => uniqid()),

// ...

Section::make('serieA')
->relationship() // this store in the DB using serieA flag
->schema([
TextInput::make('max_value_x')
->live()
->numeric()
->required(),
TextInput::make('max_value_y')
->live()
->numeric()
->required(),
Repeater::make('points')
->live()
->schema([
TextInput::make('x')->required()->live(),
TextInput::make('y')->required()->live(),
])
->columns(2)
])

// ... More series sections
TextInput::make('absolute_min_value_x')
->live()
->numeric()
->required(),
TextInput::make('absolute_max_value_x')
->live()
->numeric()
->required(),

// ... More fields for chart

Select::make('unit_measure_id')
->options([]), // List of key->value of StorageCurveUnitEnum

Livewire::make(CurveChart::class, function (Get $get) use ($graphType) {
return [
'title' => Lang::get(''),
'xLabel' => Lang::get(''),
'yLabel' =>Lang::get(''),
'is_relative' => $get('unit_measure_id') == StorageCurveUnitEnum::RELATIVE->getProp('old_code'),
'series' => [
'serieA' => [
'maxX' => $get('serieA.max_value_x'),
'maxY' => $get('serieA.max_value_y'),
'points' => $get('serieA.points')
],
// ...
'serieC' => [
'maxX' => $get('serieC.max_value_x'),
'maxY' => $get('serieC.max_value_y'),
'points' => $get('serieC.points'),
]
],
'minX' => $get('absolute_min_value_x'),
'maxX' => $get('absolute_max_value_x'),
'minY' => $get('absolute_min_value_y'),
'maxY' => $get('absolute_max_value_y'),
];
})->key(fn() => uniqid()),

// ...

Section::make('serieA')
->relationship() // this store in the DB using serieA flag
->schema([
TextInput::make('max_value_x')
->live()
->numeric()
->required(),
TextInput::make('max_value_y')
->live()
->numeric()
->required(),
Repeater::make('points')
->live()
->schema([
TextInput::make('x')->required()->live(),
TextInput::make('y')->required()->live(),
])
->columns(2)
])

// ... More series sections
This is how I'm using it.,
Dennis Koch
Dennis Koch2w ago
Oh nice. Honestly, I didn't know you can pass a Closure for the 2nd param.

Did you find this page helpful?