symfony / ux

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

[Autocomplete] + [LiveComponent] Infinite loop of requests with data-model on autocomplete. #1499

Closed Pierre90 closed 8 months ago

Pierre90 commented 9 months ago

Hi,

I've got a LiveComponent with two selects whose have data-model on them. First one to choose a "groupType", second one to choose a "companyGroup". "companyGroup" is the one with autocomplete.

So when I change my groupType, my companyGroups list has to change too. But when I change the groupType, it actually launch an infinite loop of requests on my component...

Here is my code :

Component :

#[LiveProp(writable: true)]
public ?CompanyGroupType $companyGroupType = null;

#[LiveProp(writable: true)]
public ?CompanyGroup $companyGroup = null;

#[LiveAction]
public function onCompanyGroupTypeUpdated(): void
{
      $this->companyGroups = $this->groupRepository->findByType($this->companyGroupType);
      $this->companyGroup = $this->companyGroups[0];
}

Twig :

<select class="form-control" data-model="companyGroupType" data-action="live#action" data-action-name="onCompanyGroupTypeUpdated">
    {% for type in groupTypes %}
        <option value="{{ type.id }}">
            {{ type.name }}
        </option>
    {% endfor %}
</select>
<select class="form-control my-1" data-model="companyGroup" {{ stimulus_controller('symfony/ux-autocomplete/autocomplete') }}>
    {% for group in companyGroups %}
        <option id="{{ group.id }}" value="{{ group.id }}">
            {{ group.name }}
        </option>
    {% endfor %}
</select>

Screen of the console after changed the first select :

image

I tried with a data-action instead of data-model="companyGroup" to manually change companyGroup value, same problem.

If I remove the {{ stimulus_controller('symfony/ux-autocomplete/autocomplete') }} everything work well (but no autocomplete...)

If i downgrade symfony/ux-autocomplete to 2.13.3 it works well too.

I know autocomplete and liveComponent not work very well together, but maybe is there something I miss to make this work ?

Thanks,

Pierre

smnandre commented 9 months ago

Do you see a difference in the order the Controller are initalized / connected ?

weaverryan commented 9 months ago

Fixed in #1502

To fix your issue before that PR is merged (and also verify that my fix addresses your issue), add an empty <option> to each select:

<select class="form-control" data-model="companyGroupType" data-action="live#action" data-action-name="onCompanyGroupTypeUpdated">
    <option value="">Choose a group type></option>
    {% for type in groupTypes %}
        <option value="{{ type.id }}">
            {{ type.name }}
        </option>
    {% endfor %}
</select>
<select class="form-control my-1" data-model="companyGroup" {{ stimulus_controller('symfony/ux-autocomplete/autocomplete') }}>
    <option value="">Choose a group></option>
    {% for group in companyGroups %}
        <option id="{{ group.id }}" value="{{ group.id }}">
            {{ group.name }}
        </option>
    {% endfor %}
</select>

Let me know if this workaround addresses the issue :).

Cheers!

Pierre90 commented 8 months ago

Hi @weaverryan,

Thanks a lot for your time ! It fix well the infinite loop of requests :)

But, I see another problem (with both your PR and the empty <option>) : the companyGroup select don't follow my companyGroup component value when I modify companyGroupType. In my first post, you can see I change the companyGroup value on the onCompanyGroupTypeUpdated but it's not reflect in the companyGroup select, the select is empty after the change while I have a companyGroup not null (and with a value which have a corresponding option in the select).

Edit : I don't know if can help : I tried to change my companyGroup to an ID in int instead of entity. It seems the component make two rendering (I have a loading in the twig, that is launched two times consecutively), the first with the value changed in the onCompanyGroupTypeUpdated, and a second render which modify the ID to null. With a companyGroup entity, I have two loading too, but companyGroup will not be set to null on second rendering.