symfony / ux

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

[LiveComponent] onUpdated option to update model when another is updated doesn't work #1624

Open bastien70 opened 8 months ago

bastien70 commented 8 months ago

Hey! I have a page where I display some cards.

We can sort these cards using a query or filters.

On each card we have a checkbox that will later allow us to perform mass actions

image

So in my component I've some models :

    #[LiveProp(writable: true, onUpdated: 'resetSelectedValues')]
    public ?string $query = null;

    #[LiveProp()]
    public bool $archived = false;

    #[LiveProp(writable: true)]
    public ?string $type = null;

    #[LiveProp(writable: true)]
    public array $selectedActions = []; // contains cards ids, for future mass actions

On every card, in my twig template, for the checkbox, I use that :

<input type="checkbox" class="me-2" data-model="selectedActions" value="{{ action.id }}">

Which therefore has the effect of adding the card id to the “selectedActions” model.

Except that later, if I want to apply a filter, and the card disappears from the results, the card must be unchecked.

For this I wanted to use the "onUpdated" and apply it to the "query" model. This way, when I update the search field, I reset the cards that were checked.

#[LiveProp(writable: true, onUpdated: 'resetSelectedValues')]
    public ?string $query = null;

public function resetSelectedValues(): void
    {
        $this->selectedActions = [];
    }

Except there's a problem. When I actually update the search field, the onUpdated is triggered and the $selectedActions field becomes an empty array (if I dump it, it is empty). But the modification is not "flushed". In other words, in reality, the $selectedActions has not changed at all.

I do not understand why. So I tried in the method to then call a LiveListener (which does absolutely nothing, but I told myself that it would have the effect of flushing the new value of the array), but that doesn't do anything either. Is this normal?

I am in version 2.13.3

smnandre commented 8 months ago

It's is the expected behaviour today.

You may want to use #[PostMount] hooks for resetting your other values, or dispatching an event manually on changes

bastien70 commented 8 months ago

It's is the expected behaviour today.

You may want to use #[PostMount] hooks for resetting your other values, or dispatching an event manually on changes

The PostMount is only useful for initializing the component, right? My goal is to apply a change when the $query model is updated.

To dispatch an event automatically when the model is updated, how should I go about it without the onUpdated one?

smnandre commented 8 months ago

PostMount + PostHydrate yes sorry.

See in LiveMemoryTimer:

Not 100% related to your need, but may want to take a look at the demo i made, they are some little things like that :)

smnandre commented 8 months ago

Or you may intercept the hydration but using hydrateWith

bastien70 commented 7 months ago

PostMount + PostHydrate yes sorry.

See in LiveMemoryTimer:

Not 100% related to your need, but may want to take a look at the demo i made, they are some little things like that :)

Thank you for your help :) So, for the PostHydrate in your demo. I haven't seen any documentation regarding this attribute? It is called every time a model is updated, it doesn't matter which one, if I understand correctly? I'm not sure this is enough. Because I need to check that it is the $query model that has changed.

Because I can have a $query with a value, select cards. As long as $query does not change, I have no reason to reset my table. The problem here (if I understand correctly what the attribute does) is that I can't tell which model changed?

And regarding the HydrateWith idea, it was a very good idea! I tested it, but unfortunately it didn't change anything.

#[LiveProp(writable: true, hydrateWith: 'hydrateQuery')]
    public ?string $query = null;

#[LiveProp(writable: true)]
    public array $selectedActions = [];

    public function hydrateQuery($data): ?string
    {
        $this->selectedActions = [];

        return $data;
    }

As for onUpdated, the modifications on the table are not "flush" :(

smnandre commented 7 months ago

Could you create the smallest minimal reproducer and i'll try to find you alternatives ?

As this is something i needed too in some places, i'm thinking we should find a way to ease this for everyone :)

So you'll be a kind of "patient test" on this feature :))

bastien70 commented 7 months ago

I think I just found the solution, and it’s so simple!

It is simply enough, in the twig, that the input containing the $query model also triggers a live-action :

<input type="text" class="form-control" id="team-search" placeholder="{{ 'gouvernance.team.index.search'|trans }}" data-action="live#action" data-action-name="resetSelectedActions" data-model="query"/>
#[LiveProp(writable: true)]
    public ?string $query = null;

#[LiveProp(writable: true)]
    public array $selectedActions = [];

    #[LiveAction]
    public function resetSelectedActions(): void
    {
        $this->selectedActions = [];
    }

And...it works! So we can both accumulate the model update but also trigger a live-action.

What do you think ? Is this considered a good viable solution?

smnandre commented 7 months ago

So you have 2 fetch queries right ? In what order ?

bastien70 commented 7 months ago

No, it seems that this only triggers a single request.

In the profiler I've this :

screencapture-127-0-0-1-8000-profiler-d8448b-2024-03-18-10_20_41

The query seems to contain both the targeted action but also the data corresponding to the update to be made in the $query model.

So I don't know which one is executed first? Model update or action? Hard to say

carsonbot commented 1 month ago

Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?

carsonbot commented 1 month ago

Hello? This issue is about to be closed if nobody replies.

carsonbot commented 3 weeks ago

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!