Skip to content

Commit aa4e884

Browse files
kemphakbond
authored andcommitted
[Live] Fix 'onUpdated' hook call
1 parent e1d2f19 commit aa4e884

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

src/LiveComponent/src/LiveComponentHydrator.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ public function hydrate(object $component, array $props, array $updatedProps, Li
143143
$attributes = new ComponentAttributes($dehydratedOriginalProps->getPropValue(self::ATTRIBUTES_KEY, []));
144144
$dehydratedOriginalProps->removePropValue(self::ATTRIBUTES_KEY);
145145

146+
$needProcessOnUpdatedHooks = [];
147+
146148
foreach ($componentMetadata->getAllLivePropsMetadata($component) as $propMetadata) {
147149
$frontendName = $propMetadata->calculateFieldName($component, $propMetadata->getName());
148150

@@ -215,10 +217,15 @@ public function hydrate(object $component, array $props, array $updatedProps, Li
215217
}
216218

217219
if ($propMetadata->onUpdated()) {
218-
$this->processOnUpdatedHook($component, $frontendName, $propMetadata, $dehydratedUpdatedProps, $dehydratedOriginalProps);
220+
$needProcessOnUpdatedHooks[$frontendName] = $propMetadata;
219221
}
220222
}
221223

224+
// Run 'onUpdated' hooks after all props have been initialized.
225+
foreach ($needProcessOnUpdatedHooks as $frontendName => $propMetadata) {
226+
$this->processOnUpdatedHook($component, $frontendName, $propMetadata, $dehydratedUpdatedProps, $dehydratedOriginalProps);
227+
}
228+
222229
foreach (AsLiveComponent::postHydrateMethods($component) as $method) {
223230
$component->{$method->name}();
224231
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\LiveComponent\Tests\Fixtures\Component;
13+
14+
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
15+
use Symfony\UX\LiveComponent\Attribute\LiveProp;
16+
use Symfony\UX\LiveComponent\DefaultActionTrait;
17+
use Symfony\UX\TwigComponent\Attribute\PostMount;
18+
19+
#[AsLiveComponent('with_on_updated')]
20+
final class WithOnUpdated
21+
{
22+
use DefaultActionTrait;
23+
24+
#[LiveProp(writable: true, onUpdated: 'onNumber1Updated')]
25+
public int $number1;
26+
27+
#[LiveProp]
28+
public int $number2;
29+
30+
#[LiveProp]
31+
public int $number3;
32+
33+
#[LiveProp]
34+
public int $total;
35+
36+
#[PostMount]
37+
public function postMount(): void
38+
{
39+
$this->calculateTotal();
40+
}
41+
42+
public function onNumber1Updated(): void
43+
{
44+
$this->calculateTotal();
45+
}
46+
47+
private function calculateTotal(): void
48+
{
49+
// All live props must be available to read
50+
$this->total = $this->number1 + $this->number2 + $this->number3;
51+
}
52+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<div{{ attributes }}>
2+
<label>
3+
<input type="number" data-model="number1" step="1">
4+
</label>
5+
6+
<ul>
7+
<li>Number1: {{ number1 }}</li>
8+
<li>Number2: {{ number2 }}</li>
9+
<li>Number3: {{ number3 }}</li>
10+
</ul>
11+
12+
<div>Total: {{ total }}</div>
13+
</div>

src/LiveComponent/tests/Functional/Test/InteractsWithLiveComponentsTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,19 @@ public function testCanSubmitForm(): void
179179
$this->assertSame(200, $response->getStatusCode());
180180
$this->assertStringContainsString('foobar', $testComponent->render());
181181
}
182+
183+
public function testAccessAllLivePropsInsideOnUpdatedHook(): void
184+
{
185+
$testComponent = $this->createLiveComponent('with_on_updated', [
186+
'number1' => 1,
187+
'number2' => 2,
188+
'number3' => 3,
189+
]);
190+
191+
$this->assertStringContainsString('Total: 6', $testComponent->render());
192+
193+
$testComponent->set('number1', 4);
194+
195+
$this->assertStringContainsString('Total: 9', $testComponent->render());
196+
}
182197
}

0 commit comments

Comments
 (0)