symfony / ux

Symfony UX initiative: a JavaScript ecosystem for Symfony
https://ux.symfony.com/
MIT License
820 stars 297 forks source link

[LiveComponent] Set value on LiveCollectionField #1737

Open BaptisteChabrol opened 5 months ago

BaptisteChabrol commented 5 months ago

Hello, I have a dynamicForm on a Appointment Entity. This entity has a Tracking entity relation (OneToMany).

I use the LiveCollectionField on my AppointmentForm to add dynamically a tracking. I want to set default date on a new tracking with $this->formValues['trackings'][$index] = ['date' => new \DateTime()];

But when I click on the add button, I have this error : Unable to dehydrate value of type "array" for property "formValues" on component "App\Twig\Components\AppointmentForm". Change this to a simpler type of an object that can be dehydrated. Or set the hydrateWith/dehydrateWith options in LiveProp or set "useSerializerForHydration: true" on the LiveProp to use the serializer.

When I try to set useSerializerForHydration like this : #[LiveProp(useSerializerForHydration: true)] public ?Appointment $initialFormData = null;

I have this error (I have 2 relations with the User entity in Tracking, ManyToMany and ManyToOne) : Error rendering "AppointmentForm" component: A circular reference has been detected when serializing the object of class "Proxies\__CG__\App\Entity\User" (configured limit: 1).

smnandre commented 5 months ago

So you need to help the serializer there :)

You can probably solve this with one of the following solutions:

See https://symfony.com/bundles/ux-live-component/current/index.html#hydrating-with-the-serializer for details

If i were you, i'll try in isolation (outside the livecomponent) to dehydrate your object with the Serializer service, and then bring this configuration in the LiveProp.. it will be much easier to test/debug :)

norkunas commented 5 months ago

formValues supposed to store scalarsnormalized values, so it should be a datetime string instead of an object

BaptisteChabrol commented 5 months ago

Thanks for your feedback. The problem was with the serialization of my User entity, i needed to use the Groups annotation to normalize all fields of my Appointment entity (without id), all Tracking fields (without id and appointment) and the User id.

So to set default value on my new Tracking with the LiveCollectionField, I do this :

(Form)

    use LiveCollectionTrait {
        addCollectionItem as traitAddCollectionItem;
    }

    ....

    #[LiveAction]
    public function addCollectionItem(PropertyAccessorInterface $propertyAccessor, #[LiveArg] string $name): void
    {
        $this->traitAddCollectionItem($propertyAccessor, $name);

       // to get index of the created Tracking
        $propertyPath = $this->fieldNameToPropertyPath($name, $this->formName);
        $data = $propertyAccessor->getValue($this->formValues, $propertyPath);
        $index = [] !== $data ? max(array_keys($data)) : 0;

        /** @var User $currentUser */
        $currentUser = $this->security->getUser();
        $tracking = (new Tracking())->setDate(new \DateTime());

        $this->formValues['trackings'][$index] = $this->normalizer->normalize($tracking, null, ['groups' => 'tracking']);
        $this->formValues['trackings'][$index]['user'] = $currentUser->getId();
    }

I don't know if this is the best solution but it works. Thanks for your help