Skip to content

Commit 9c870b4

Browse files
committed
[Live] Fixing a bug where parent component model would be used to set child model field
1 parent 6040306 commit 9c870b4

File tree

5 files changed

+54
-8
lines changed

5 files changed

+54
-8
lines changed

src/LiveComponent/assets/dist/live_controller.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,9 @@ class SetValueOntoModelFieldsPlugin {
21122112
if (element instanceof HTMLFormElement) {
21132113
return;
21142114
}
2115+
if (!elementBelongsToThisComponent(element, component)) {
2116+
return;
2117+
}
21152118
const modelDirective = getModelDirectiveFromElement(element);
21162119
if (!modelDirective) {
21172120
return;

src/LiveComponent/assets/src/Component/plugins/SetValueOntoModelFieldsPlugin.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Component from '../index';
22
import {
3+
elementBelongsToThisComponent,
34
getModelDirectiveFromElement,
45
getValueFromElement,
56
setValueOnElement
@@ -38,6 +39,10 @@ export default class implements PluginInterface {
3839
return;
3940
}
4041

42+
if (!elementBelongsToThisComponent(element, component)) {
43+
return;
44+
}
45+
4146
const modelDirective = getModelDirectiveFromElement(element);
4247
if (!modelDirective) {
4348
return;

src/LiveComponent/assets/test/controller/model.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,45 @@ describe('LiveController data-model Tests', () => {
628628
expect(commentField.value).toEqual('MMMM SO GOOD');
629629
});
630630

631+
it('does not try to set the value of inputs inside a child component', async () => {
632+
const test = await createTest({ comment: 'cookie', childComment: 'mmmm' }, (data: any) => `
633+
<div ${initComponent(data)}>
634+
<textarea data-model="comment" id="parent-comment"></textarea>
635+
636+
<div ${initComponent({ comment: data.childComment }, {}, {id: 'the-child-id'})}>
637+
<textarea data-model="comment" id="child-comment"></textarea>
638+
</div>
639+
</div>
640+
`);
641+
642+
const commentField = test.element.querySelector('#parent-comment');
643+
if (!(commentField instanceof HTMLTextAreaElement)) {
644+
throw new Error('wrong type');
645+
}
646+
expect(commentField.value).toEqual('cookie');
647+
648+
const childCommentField = test.element.querySelector('#child-comment');
649+
if (!(childCommentField instanceof HTMLTextAreaElement)) {
650+
throw new Error('wrong type');
651+
}
652+
expect(childCommentField.value).toEqual('mmmm');
653+
654+
// NOW we will re-render
655+
test.expectsAjaxCall('get')
656+
.expectSentData(test.initialData)
657+
// change the data to be extra tricky
658+
.serverWillChangeData((data) => {
659+
data.comment = 'i like apples';
660+
})
661+
.init();
662+
663+
await test.component.render();
664+
665+
expect(commentField.value).toEqual('i like apples');
666+
// child component should not have been re-rendered
667+
expect(childCommentField.value).toEqual('mmmm');
668+
});
669+
631670
it('keeps the unsynced value of an input on re-render, but accepts other changes to the field', async () => {
632671
const test = await createTest({
633672
comment: 'Live components',

src/LiveComponent/tests/Functional/EventListener/AddLiveAttributesSubscriberTest.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,13 @@
1919
*/
2020
final class AddLiveAttributesSubscriberTest extends KernelTestCase
2121
{
22+
use HasBrowser;
2223
/**
2324
* The deterministic id of the "todo_item" components in todo_list.html.twig.
2425
* If that template changes, this will need to be updated.
2526
*/
2627
public const TODO_ITEM_DETERMINISTIC_PREFIX = 'live-289310975-';
2728

28-
use HasBrowser;
29-
3029
public function testInitLiveComponent(): void
3130
{
3231
$div = $this->browser()
@@ -91,8 +90,8 @@ public function testItAddsIdAndFingerprintToChildComponent(): void
9190

9291
$lis = $ul->children('li');
9392
// deterministic id: should not change, and counter should increase
94-
$this->assertSame(self::TODO_ITEM_DETERMINISTIC_PREFIX . '0', $lis->first()->attr('data-live-id'));
95-
$this->assertSame(self::TODO_ITEM_DETERMINISTIC_PREFIX . '2', $lis->last()->attr('data-live-id'));
93+
$this->assertSame(self::TODO_ITEM_DETERMINISTIC_PREFIX.'0', $lis->first()->attr('data-live-id'));
94+
$this->assertSame(self::TODO_ITEM_DETERMINISTIC_PREFIX.'2', $lis->last()->attr('data-live-id'));
9695

9796
// fingerprints
9897
// first and last both have the same input - thus fingerprint

src/LiveComponent/tests/Functional/EventListener/InterceptChildComponentRenderSubscriberTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ final class InterceptChildComponentRenderSubscriberTest extends KernelTestCase
2525
// if you pass in 3 "items" with data that matches what's used by default
2626
// in buildUrlForTodoListComponent
2727
private static array $actualTodoItemFingerprints = [
28-
AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX . '0' => 'LwqODySoRx3q+v64EzalGouzpSHWKIm0jENTUGtQloE=',
29-
AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX . '1' => 'gn9PcPUqL0tkeLSw0ZuhOj96dwIpiBmJPoO5NPync2o=',
30-
AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX . '2' => 'ndV00y/qOSH11bjOKGDJVRsxANtbudYB6K8D46viUI8=',
28+
AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX.'0' => 'LwqODySoRx3q+v64EzalGouzpSHWKIm0jENTUGtQloE=',
29+
AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX.'1' => 'gn9PcPUqL0tkeLSw0ZuhOj96dwIpiBmJPoO5NPync2o=',
30+
AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX.'2' => 'ndV00y/qOSH11bjOKGDJVRsxANtbudYB6K8D46viUI8=',
3131
];
3232

3333
public function testItAllowsFullChildRenderOnMissingFingerprints(): void
@@ -79,7 +79,7 @@ public function testItRendersEmptyElementOnMatchingFingerprintWithCustomDataLive
7979
public function testItRendersNewPropWhenFingerprintDoesNotMatch(): void
8080
{
8181
$fingerprints = self::$actualTodoItemFingerprints;
82-
$fingerprints[AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX . '1'] = 'wrong fingerprint';
82+
$fingerprints[AddLiveAttributesSubscriberTest::TODO_ITEM_DETERMINISTIC_PREFIX.'1'] = 'wrong fingerprint';
8383

8484
$this->browser()
8585
->visit($this->buildUrlForTodoListComponent($fingerprints))

0 commit comments

Comments
 (0)