Skip to content

[LiveComponent] Updated values not submitted to the server properly #1557

@lemorragia

Description

@lemorragia

I've got an update problem, with 2.14.2 version of twig+live components. The use case is: a Sale Order has many items. I'm using a Live Component + Form + LiveCollectionType.
Every item has a "product", a "price", a "quantity" and an "untaxedTotal". Ideally when you select a product, the price is updated with the product salePrice, and when you change quantity or price on the SaleOrderItem, the untaxedTotal is also updated.

OrderComponent

#[AsLiveComponent] final class OrderComponent extends AbstractController { use ComponentWithFormTrait; use DefaultActionTrait; use LiveCollectionTrait; #[LiveProp(writable: true)] public ?SaleOrderInput $initialFormData = null; protected function instantiateForm(): FormInterface { return $this->createForm(OrderType::class, $this->initialFormData); } #[LiveAction] public function updateUnitPrice(): void { foreach ($this->formValues['items'] as &$item) { $item['unitPrice'] = rand(0, 40); if (empty($item['quantity'])) { $item['quantity'] = 1; } $this->setUntaxedTotal($item); } } #[LiveAction] public function updateUntaxedTotal(): void { foreach ($this->formValues['items'] as &$item) { $this->setUntaxedTotal($item); } } private function setUntaxedTotal(array &$item): void { $item['untaxedTotal'] = $item['unitPrice'] * $item['quantity'] - $item['discount']; } } 

and the relative form (simplified):

class OrderType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder ->add('items', LiveCollectionType::class, [ 'entry_type' => OrderItemType::class, 'entry_options' => ['label' => false], 'label' => false, 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, ]) ; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => SaleOrderInput::class ]); } } 

also the OrderItemType:

class OrderItemType extends AbstractType { /** @param array<string, mixed> $options */ public function buildForm(FormBuilderInterface $builder, array $options): void { $builder = new DynamicFormBuilder($builder); $builder ->add('product', EntityType::class, [ 'class' => Product::class, 'required' => false, 'label' => 'wd.field.product', 'autocomplete' => true, 'attr' => [ 'placeholder' => 'wd.field.product', 'data-action' => 'live#action', 'data-action-name' => 'updateUnitPrice', ], ]) ->add('quantity', NumberType::class, [ 'label' => 'wd.field.quantity', 'scale' => 1, 'required' => true, 'html5' => true, 'attr' => [ 'data-action' => 'live#action', 'data-action-name' => 'updateUntaxedTotal', ], ]) ->add('unitPrice', NumberType::class, [ 'label' => 'wd.field.unitPrice', 'scale' => 1, 'required' => true, 'html5' => true, 'attr' => [ 'data-action' => 'live#action', 'data-action-name' => 'updateUntaxedTotal', ], ]) ->add('untaxedTotal', NumberType::class, [ 'label' => 'wd.field.total', 'attr' => [ 'readonly' => true, ], ]) ; [..] } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => SaleOrderItemInput::class, ]); } } 

When i select a product all the form fields are updated correctly. The problem is that when i try to change manually quantity or unitPrice, the untaxedTotal stays always "one step back".
Let's say that unitPrice is 1 and quantity is 1, if i click to increase the NumberType or if i manually edit the number to "2" a UX ajax call is made, with an empty "updated" object. On the second change (to "3") another call is made with an updated object containing "2" as the new value. This is true with an "html5"-> false setting, or even with a TextType as form field.

Something funny could be going on between HTML/DOM and UX, because on the first change the value attribute in the html "rightfully" remains "one step behind" (so on the first change, the value remains "1" in the HTML). So maybe i'm wrong using a LiveAction to update the form data for this use case, or some additional javascript is required to force the value of the HTML to match the one displayed, or UX is not catching the proper updated value correctly. In the most basic test "add a collection element"->"select a product"->"increase the unitPrice by 1" it seems to me that UX should send the updated value inside the "updated" object of the ajax call. Any ideas about why this is happening?

EDIT: i actually built a simple prototype, and the behaviour is the same. On further testing, if i keep the focus on the fields and as long as i edit them by typing, all the ajax calls are made, but the value is never changed, even after N edits. If i edit the field, lose the focus, and edit it again, the values start to change (but always "one step back"). I also tried a different syntax to bind to different events (eg. "keyup->live#action") but with no change, i doubt that the problem is event binding, because when i edit the field the ajax calls are always launched correctly, even though with "not updated data". This is also true with twig/live components 2.15.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions