Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LiveComponent] All onUpdated methods are triggered #2454

Open
jkgroupe opened this issue Dec 19, 2024 · 6 comments
Open

[LiveComponent] All onUpdated methods are triggered #2454

jkgroupe opened this issue Dec 19, 2024 · 6 comments
Labels
LiveComponent Status: Waiting Feedback Needs feedback from the author

Comments

@jkgroupe
Copy link

Hello,

I am using live components on Symfony 6.4 and when I add onUpdated parameters, all methods are triggered when I update just one element

Live Component

#[AsLiveComponent]
class RevenueChart
{
    use DefaultActionTrait;

    #[LiveProp(writable: true, onUpdated: 'onChangeYear')]
    public ?int $currentYear = null;

    #[LiveProp(writable: true, onUpdated: 'onChangeTarget')]
    public float $currentTarget = 0.0;

    public function onChangeTarget($oldValue): void
    {
        var_dump($oldValue);
    }

    public function onChangeYear($oldValue): void
    {
        var_dump($oldValue);
    }
}

Twig
<select data-model="on(change)|currentYear" id="year"></select>

<input type="number" data-model="on(change)|currentTarget" class="form-control" id="target" />

I don't know if I'm missing something but it doesn't work in my case

Thanks for your help

@jkgroupe jkgroupe added the Bug Bug Fix label Dec 19, 2024
@smnandre
Copy link
Member

I could not reproduce your problem, could you provide a github repository with a minimal symfony app showing the issue happenign ?

@smnandre smnandre added Status: Waiting Feedback Needs feedback from the author and removed Status: Needs Review Needs to be reviewed labels Dec 20, 2024
@jkgroupe
Copy link
Author

jkgroupe commented Jan 7, 2025

Hello, I've reproduced this issue with UX demo. I don't know if this is a normal behavior but all events are triggered when I change just one field value

Hope it can help

src/Twig/Components/DinoChart.php

<?php

namespace App\Twig\Components;

use App\Service\DinoStatsService;
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;
use Psr\Log\LoggerInterface;

#[AsLiveComponent]
class DinoChart
{
    use DefaultActionTrait;

    #[LiveProp(writable: true, onUpdated: 'onTypesUpdated')]
    public array $currentTypes = ['all', 'large theropod', 'small theropod'];

    #[LiveProp(writable: true, onUpdated: 'onFromYearUpdated')]
    public int $fromYear = -200;

    #[LiveProp(writable: true, onUpdated: 'onToYearUpdated')]
    public int $toYear = -65;

    public function __construct(
        private DinoStatsService $dinoStatsService,
        private ChartBuilderInterface $chartBuilder,
        private LoggerInterface $logger,
    ) {
    }

    #[ExposeInTemplate]
    public function getChart(): Chart
    {
        $chart = $this->chartBuilder->createChart(Chart::TYPE_LINE);
        $chart->setData($this->dinoStatsService->fetchData(
            $this->fromYear,
            $this->toYear,
            $this->currentTypes
        ));

        $chart->setOptions([
            // set title plugin
            'plugins' => [
                'title' => [
                    'display' => true,
                    'text' => \sprintf(
                        'Dinos species count from %dmya to %dmya',
                        abs($this->fromYear),
                        abs($this->toYear)
                    ),
                ],
                'legend' => [
                    'labels' => [
                        'boxHeight' => 20,
                        'boxWidth' => 50,
                        'padding' => 20,
                        'font' => [
                            'size' => 14,
                        ],
                    ],
                ],
            ],
            'elements' => [
                'line' => [
                    'borderWidth' => 5,
                    'tension' => 0.25,
                    'borderCapStyle' => 'round',
                    'borderJoinStyle' => 'round',
                ],
            ],
            'maintainAspectRatio' => false,
        ]);

        return $chart;
    }

    #[ExposeInTemplate]
    public function allTypes(): array
    {
        return DinoStatsService::getAllTypes();
    }

    public function onFromYearUpdated(): void
    {
        $this->logger->error("on from year updated");
    }

    public function onToYearUpdated(): void
    {
        $this->logger->error("on to year updated");
    }

    public function onTypesUpdated(): void
    {
        $this->logger->error("on types updated");
    }
}

templates/components/DinoChart.html.twig

<div {{ attributes }}>
    <div class="row">
        <div class="col-2">
            <label for="fromYear" class="form-label">
                From: <code><small>({{ fromYear|abs }} mya)</small></code>
            </label>
            <select data-model="fromYear" id="fromYear" data-controller="symfony--ux-autocomplete--autocomplete">
                {% for year in -200..toYear %}
                    <option value="{{ year }}">{{ year }}</option>
                {% endfor %}
            </select>
        </div>

        <div class="col-2">
            <label for="toYear" class="form-label">
                To: <code><small>({{ toYear|abs }} mya)</small></code>
            </label>
            <select data-model="toYear" id="toYear" data-controller="symfony--ux-autocomplete--autocomplete">
                {% for year in fromYear..-65 %}
                    <option value="{{ year }}">{{ year }}</option>
                {% endfor %}
            </select>
        </div>

        <div class="col-8">
            <label for="dinoTypes" class="form-label">Choose Dino Types</label>
            <select
                data-model="currentTypes"
                multiple
                id="dinoTypes"
                data-controller="symfony--ux-autocomplete--autocomplete"
            >
                {% for type in allTypes %}
                    <option value="{{ type }}">{{ type }}</option>
                {% endfor %}
            </select>
        </div>
    </div>

    <hr>

    <div style="min-height: 480px; margin-bottom: 1.5rem;">
        {{ render_chart(chart) }}
    </div>

    <small>Source:
        <a href="https://www.nhm.ac.uk/" class="link">National History Museum</a> courtesy of
        <a href="https://github.com/kjanjua26/jurassic-park" class="link">https://github.com/kjanjua26/jurassic-park</a>
    </small>
</div>

Logs when I updated one field
Capture d’écran 2025-01-07 à 13 01 09

POST request

-----------------------------199506608811236724691681381630
Content-Disposition: form-data; name="data"

{"props":{"currentTypes":["all","large theropod","small theropod","ceratopsian"],"fromYear":-200,"toYear":-89,"@attributes":{"id":"live-895539465-0"},"@checksum":"wPd53Ju4RJcoKHAW45ly6OCMsfZ1JsfZZRI5zq/6K4c="},"updated":{"fromYear":"-193","toYear":"-89"}}
-----------------------------199506608811236724691681381630--

@smnandre
Copy link
Member

smnandre commented Jan 8, 2025

I tried with the demo and everything works as expected. One event per field.

Enregistrement.de.l.ecran.2025-01-08.a.04.17.13.mov

With your code, any change in fromYear has impact on the toYear select... and any change in toYear has an impact on the fromYears select... in some way you try to change your LiveProps by changing the HTML, and this cannot be done that way.

 <select data-model="fromYear" id="fromYear" data-controller="symfony--ux-autocomplete--autocomplete">
    {% for year in -200..toYear %}
         <option value="{{ year }}">{{ year }}</option>
    {% endfor %}
</select>

Also it seems you added an autocomplete on both ? Having both autocomplete and cross-changes in the HTML at the same time is not helping i suppose.

@smnandre smnandre removed the Bug Bug Fix label Jan 8, 2025
@jkgroupe
Copy link
Author

jkgroupe commented Jan 8, 2025

That works if I have 2 range fields and 1 select field but I still have the issue if I have more than 1 select even if I remove autocomplete controllers

<div class="col-2">
    <label for="fromYear" class="form-label">
        From: <code><small>({{ fromYear|abs }} mya)</small></code>
    </label>
    <select data-model="fromYear" id="fromYear">
        {% for year in -200..toYear %}
            <option value="{{ year }}">{{ year }}</option>
        {% endfor %}
    </select>
</div>

<div class="col-2">
    <label for="toYear" class="form-label">
        To: <code><small>({{ toYear|abs }} mya)</small></code>
    </label>
    <select data-model="toYear" id="toYear">
        {% for year in fromYear..-65 %}
            <option value="{{ year }}">{{ year }}</option>
        {% endfor %}
    </select>
</div>

<div class="col-8">
    <label for="dinoTypes" class="form-label">Choose Dino Types</label>
    <select
        data-model="currentTypes"
        multiple
        id="dinoTypes"
    >
        {% for type in allTypes %}
            <option value="{{ type }}">{{ type }}</option>
        {% endfor %}
    </select>
</div>

Capture d’écran 2025-01-08 à 10 21 59

@smnandre
Copy link
Member

smnandre commented Jan 8, 2025

Replace

 <select data-model="fromYear" id="fromYear">
        {% for year in -200..toYear %}
            <option value="{{ year }}">{{ year }}</option>
        {% endfor %}
    </select>
</div>

<div class="col-2">
    <label for="toYear" class="form-label">
        To: <code><small>({{ toYear|abs }} mya)</small></code>
    </label>
    <select data-model="toYear" id="toYear">
        {% for year in fromYear..-65 %}
            <option value="{{ year }}">{{ year }}</option>
        {% endfor %}
    </select>

with

 <select data-model="fromYear" id="fromYear">
        {% for year in -100..0 %}
            <option value="{{ year }}">{{ year }}</option>
        {% endfor %}
    </select>
</div>

<div class="col-2">
    <label for="toYear" class="form-label">
        To: <code><small>({{ toYear|abs }} mya)</small></code>
    </label>
    <select data-model="toYear" id="toYear">
        {% for year in 0..100 %}
            <option value="{{ year }}">{{ year }}</option>
        {% endfor %}
    </select>

Do you still have the problem ?

@jkgroupe
Copy link
Author

jkgroupe commented Jan 8, 2025

Yes I still have the issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LiveComponent Status: Waiting Feedback Needs feedback from the author
Projects
None yet
Development

No branches or pull requests

3 participants