Custom Page & Dynamic Forms, entanglement issues

Morning... Anyone got any suggestions on the best way to deal with a filament page that uses a dynamic form. The form is built from a database of fields, and ends up with assigned name\id such as 'textArea40' But I can't assign the statics in the Page class, as I don't know what they are called. I can get the form dynamically, so I can 'see' the fields, but I don't know how to get everything out where there are nested components, and secondly, if I could get an array of all the name\id's, how to apply that so Livewire can do its thing. I end up with a lot of console errors like: Livewire Entangle Error: Livewire property ['textArea40'] cannot be found on component: ['area.persona.filament.pages.edoc-complete'] Any help gratefully received.
12 Replies
toeknee
toeknee5mo ago
You just need to data set the form? And ensure you build the form in php... So it's all build and the fields are dynamic then and stored in the data set. Ideally providing what you have built can be helpful.
Matthew
MatthewOP5mo ago
If you have fields with random names like
protected function getFormSchema(): array
{
$fieldName = 'fullName' . rand(1000, 9999);

return [
Section::make('User Details')

->schema([ TextInput::make($fieldName)

];
}
protected function getFormSchema(): array
{
$fieldName = 'fullName' . rand(1000, 9999);

return [
Section::make('User Details')

->schema([ TextInput::make($fieldName)

];
}
how do you extract these nested form ids to apply to the data set
Majid Al Zariey
Majid Al Zariey5mo ago
arent you getting them in the $data array?
toeknee
toeknee5mo ago
they should be stored in the $data array? But if you shouldn't use random ranmes that's wrong. If you have multiple names you need to allow a repeater option which then unique keys it as an array set.
Dennis Koch
Dennis Koch5mo ago
Use the ->statePath('data') and store all the data in the $data property
Matthew
MatthewOP5mo ago
The use of the random names is because the form fields are dynamic. They are built by the users, so fields are added, and we can't hard code the names as there might be more than one instance of the same field. They go into the $data array fine. It is more the issue that because I am not directly defining the relevant fieldnames in the page, they get entanglement issues raised. This causes an issue for a field like a field upload, as I can't reference it in the blade to deal with the submit button being unavailable whilst an upload is happening. TBH - my livewire knowledge and custom pages is very weak, so I need to investigate this a bit more to be able to clearly explain what needs addressing.
Dennis Koch
Dennis Koch5mo ago
That Livewire errors sounds like it's not using the correct state path. Can you share more of your code?
LeandroFerreira
LeandroFerreira5mo ago
I think you should add statePath and $this->form->fill() in the mount method. In your example, each time the form renders, the field name changes. Try it:
public ?array $data = [];

public $fieldName = '';
public function mount(): void
{
$this->fieldName = 'fullName'.rand(1000, 9999);
$this->form->fill();
}

public function form(Form $form): Form
{
return $form
->schema([
TextInput::make($this->fieldName),
])
->statePath('data');
}
public ?array $data = [];

public $fieldName = '';
public function mount(): void
{
$this->fieldName = 'fullName'.rand(1000, 9999);
$this->form->fill();
}

public function form(Form $form): Form
{
return $form
->schema([
TextInput::make($this->fieldName),
])
->statePath('data');
}
Matthew
MatthewOP5mo ago
Ummm...the issue may have been that I hadn't included
InteractsWithForms
InteractsWithForms
in my page class All the entanglement issues have disappeared. My only problem now is getting the submit button to spin\disable when there is a File Upload happening. Here is my page class:
namespace App\Area\Persona\Filament\Pages;

use ...import classes...

class EdocComplete extends Page implements HasForms
{
use InteractsWithForms;

protected static string $layout = 'area.persona.filament.pages.partials.edoc-complete-layout';

protected static string|array $routeMiddleware = [CheckEdocExistsAndNoResponse::class];

protected static string $view = 'area.persona.filament.pages.edoc-complete';

public EdocRequest $edocRequest;

public ClientDocTemplates $template;

public ?array $data = [];

public function mount() : void
{

$this->edocRequest = request()->attributes->get('edocRequest');

$this->template = request()->attributes->get('template');

$this->form->fill();
}

protected function getFormSchema() : array
{

return $this->template->getTemplateForm();

}

public function form(Form $form) : Form
{
return $form
->schema($this->getFormSchema())
->statePath('data');
}

public function getHeader() : View
{
return view('area.persona.filament.pages.partials.edoc-complete-header', [
'edocRequest' => $this->edocRequest, 'template' => $this->template,
]);
}

protected function getHeaderActions() : array
{
return [

Action::make('Return')
->button()
->action(function () {
return redirect()->route('filament.persona.resources.e-docs.index', [
'tenant' => Filament::getTenant()->getUuid(),
]);
}),

];
}

public function submit() : void
{
$formDataHandler = new FormDataHandler;

$formDataHandler->handle($this->data, $this->edocRequest);
}
}
namespace App\Area\Persona\Filament\Pages;

use ...import classes...

class EdocComplete extends Page implements HasForms
{
use InteractsWithForms;

protected static string $layout = 'area.persona.filament.pages.partials.edoc-complete-layout';

protected static string|array $routeMiddleware = [CheckEdocExistsAndNoResponse::class];

protected static string $view = 'area.persona.filament.pages.edoc-complete';

public EdocRequest $edocRequest;

public ClientDocTemplates $template;

public ?array $data = [];

public function mount() : void
{

$this->edocRequest = request()->attributes->get('edocRequest');

$this->template = request()->attributes->get('template');

$this->form->fill();
}

protected function getFormSchema() : array
{

return $this->template->getTemplateForm();

}

public function form(Form $form) : Form
{
return $form
->schema($this->getFormSchema())
->statePath('data');
}

public function getHeader() : View
{
return view('area.persona.filament.pages.partials.edoc-complete-header', [
'edocRequest' => $this->edocRequest, 'template' => $this->template,
]);
}

protected function getHeaderActions() : array
{
return [

Action::make('Return')
->button()
->action(function () {
return redirect()->route('filament.persona.resources.e-docs.index', [
'tenant' => Filament::getTenant()->getUuid(),
]);
}),

];
}

public function submit() : void
{
$formDataHandler = new FormDataHandler;

$formDataHandler->handle($this->data, $this->edocRequest);
}
}
LeandroFerreira
LeandroFerreira5mo ago
same error? Does it work if you change the schema?
protected function getFormSchema(): array
{
return [
TextInput::make('field')
];
}
protected function getFormSchema(): array
{
return [
TextInput::make('field')
];
}
Matthew
MatthewOP5mo ago
We’re good now with the entanglement. Now the issue is the File Upload fiields. Within resources, the submit button disables whilst files are uploading, preventing submission before the file upload is complete. With the page, thos doesn’t behave the same way. So you can submit whilst a file is uploading, and then it never reachea the data array
LeandroFerreira
LeandroFerreira5mo ago
use $this->form->getState() to validade the form and get the data https://filamentphp.com/docs/3.x/forms/adding-a-form-to-a-livewire-component#adding-the-form If you need to access the TemporaryUploadedFile in the data array, add dehydrated() to the FileUpload field

Did you find this page helpful?