ux
ux copied to clipboard
[LiveComponent] [Autocomplete] Autocomplete with custom data endpoint not working in a live component
I have a problem when I use an autocomplete field, which uses a custom endpoint, together with a live component. I have simplified my case and added the files below. The problem is that when I select something in the autocomplete field, the message “The selected choice is invalid.” appears:
If I then click on “Save”, a message appears that I should select an element from the list, even though I have selected one:
Versions:
- symfony/form: 7.0.7
- symfony/ux-autocomplete: 2.17.0
- symfony/ux-live-component: 2.17.0
This is my form type:
<?php
namespace App\Form;
use App\Struct\TestFormStruct;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class TestFormType extends AbstractType
{
public function __construct(
private readonly UrlGeneratorInterface $router,
) {
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('testField', ChoiceType::class, [
'placeholder' => 'Please select...',
'autocomplete' => true,
'autocomplete_url' => $this->router->generate('api_test'),
'options_as_html' => true,
'no_more_results_text' => '',
]);
$builder->add('save', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => TestFormStruct::class,
]);
}
}
This is my TestFormStruct:
<?php
namespace App\Struct;
class TestFormStruct
{
private ?string $testField = null;
public function getTestField(): ?string
{
return $this->testField;
}
public function setTestField(?string $testField): void
{
$this->testField = $testField;
}
}
This is the autocomplete_url action:
#[Route('/test', name: 'api_test', methods: ['GET'])]
public function test(): JsonResponse
{
return $this->json([
'results' => [
'options' => [
[
'value' => '1',
'text' => 'Pizza',
'group_by' => 'food',
],
[
'value' => '2',
'text' => 'Banana',
'group_by' => 'food',
],
],
'optgroups' => [
[
'value' => 'food',
'label' => 'food',
]
],
],
]);
}
This is my live component:
<?php
declare(strict_types=1);
namespace App\Twig\Components;
use App\Form\TestFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;
#[AsLiveComponent]
class TestForm extends AbstractController
{
use ComponentWithFormTrait;
use DefaultActionTrait;
protected function instantiateForm(): FormInterface
{
return $this->createForm(TestFormType::class);
}
}
And this is the template of my live component:
<div {{ attributes }}>
{{ form_start(form) }}
{{ form_row(form.testField) }}
{{ form_end(form) }}
</div>
The component is added to a page with this: <twig:TestForm />
Does anyone have any idea what the problem is?
You should start by setting a LiveProp with the data you want to use in your form (a TestFormStruct instance i guess): https://symfony.com/bundles/ux-live-component/current/index.html#forms
Then, some first questions to maybe give you some ideas / leads #1844
Can you look in the DOM & your browser inspector what is happening ? When is the error thrown ? What is the initial state ? Can you submit without changing the field ? Is your ajax endpoint called ? Does it work if you use a standard form and not a live one ? If so, does it work with a Autocomplete with hard-coded choices ?
You should start by setting a LiveProp with the data you want to use in your form (a TestFormStruct instance i guess): https://symfony.com/bundles/ux-live-component/current/index.html#forms
Ok, I thought that was optional. I've added it, but unfortunately it hasn't changed anything yet.
When is the error thrown ? What is the initial state ?
When I click in the selection field, a request is sent to the endpoint to load the options. Then the options are displayed and when I select an option, the live component is re-rendered. A request is then sent to the live component and this then fails with a 422 and returns the HTML, which then contains the message “The selected choice is invalid.”. This is the payload that is sent to the endpoint to re-render the live component after I select an option:
{"props":{"initialFormData":{"testField":null},"formName":"test_form","test_form":{"testField":"","save":null,"_token":"..."},"isValidated":false,"validatedFields":[],"@attributes":{"id":"live-3754781061-0"},"@checksum":"..."},"updated":{"test_form.testField":"1","validatedFields":["test_form.testField"]}}
Can you submit without changing the field ?
No, the browser stops me with the message from my second screenshot, because the field is required.
Is your ajax endpoint called ?
Yes, as soon as I click in the field
Does it work if you use a standard form and not a live one ?
Yes, this works, but I need a live form as I need dependent fields in my real case, like in this example.
If so, does it work with a Autocomplete with hard-coded choices ?
Yes, the live form with hardcoded choices works
I found out that I can work around the problem by setting 'required' => false in my field, adding the following line and then validating the field manually when submitting.
$builder->get('testField')->resetViewTransformers();
But I don't think that's a nice solution.
I think the problem is that the options loaded via Ajax are missing in the ChoiceList of the form field. A special “choice_loader” was used for the Entity Autocomplete, which I think must also be done for the Ajax Autocomplete. But I haven't come up with a solution yet.
Maybe try this ? https://github.com/symfony/ux/issues/391#issuecomment-2139592202`
Maybe try this ? https://github.com/symfony/ux/issues/391#issuecomment-2139592202
No, unfortunately that doesn't help. In my case, it's not about an entity autocomplete. My custom Ajax endpoint, which loads the options, sends a request to an external API. So it would also be bad to have to call the external API again in a custom “choice_loader” (because of rate limits).
Or should I still do it with the 'required' => false and the resetViewTransformers to skip the standard validation and then do it myself when submitting the form? But it would still be nice if there was a clean standard solution for this case that was also documented. It's actually not an unusual case in my opinion.
Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?
I just ran into this problem with the latest version (2.22.0) and it is still happening.
Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?
Could I get a reply or should I close this?
Hey,
I didn't hear anything so I'm going to close it. Feel free to comment if this is still relevant, I can always reopen!