Closed manuelkiessling closed 1 year ago
I had a similar issue until I compiled the assets (the javascript was updated too).
@xaviermarchegay I've also run npm run update
and npm run build
, but this doesn't change the situation for me. I've verified that the NPM dependencies have also been updated to the 2.5.0 version.
Thanks for the very clear bug report including the payloads before and after! And yes, there were quite a few BC-breaking changes, but what you're experiencing should not be happening.
Your 2.5 payload, indeed, looks way too small. Apart from many of your models being missing, it's obviously missing the _checksum
. What does your root component element look like when it's rendered? Specifically, the data-live-data-value
attribute would be interesting. It should, among other things, contain the _checksum
. Also, when you hit this error, is it the first Ajax call that your component has made? Or has it made any others?
Cheers!
It's the first one. I've digged into it for a while now, but still have no idea where this issue comes from. Therefore, allow me to share some more code.
First, here is the gist of my LiveComponent:
<?php
#[AsLiveComponent(
'videobasedmarketing_recordings_video_manage_widget',
'@videobasedmarketing.recordings/video_manage_widget_live_component.html.twig'
)]
class VideoManageWidgetLiveComponent
extends AbstractController
{
use DefaultActionTrait;
use ComponentWithFormTrait;
#[LiveProp(fieldName: 'data')]
public ?Video $video = null;
#[LiveProp]
public bool $editModalIsOpen = false;
public function mount(
Video $video
)
{
$this->denyAccessUnlessGranted(
VotingAttribute::Edit->value,
$video
);
$this->video = $video;
}
#[LiveAction]
public function showEditModal(): void
{
$this->editModalIsOpen = true;
}
#[LiveAction]
public function hideEditModal(): void
{
$this->editModalIsOpen = false;
}
protected function instantiateForm(): FormInterface
{
return $this->createForm(
VideoType::class,
$this->video
);
}
}
Here is - again only the "gist" - of the component template:
{# @var this \App\VideoBasedMarketing\Recordings\Presentation\Component\VideoManageWidgetLiveComponent #}
{# @var TwigHelperService \App\Shared\Presentation\Service\TwigHelperService #}
<div {{ attributes }}>
<button
class="p-2 pl-4 pr-4 w-full h-full text-left text-sm"
data-action="live#action"
data-action-name="showEditModal"
>
<span class="flex flex-row justify-between items-center gap-2">
<span>
Aufnahme bearbeiten
</span>
<span>
{# Heroicon: pencil-square solid #}
<svg
class="h-4 w-4 text-indigo-900"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="..." />
<path d="..." />
</svg>
</span>
</span>
</button>
</div>
And finally, here is the result, fresh from the rendered DOM:
<div data-controller="live" data-live-url-value="/_components/videobasedmarketing_recordings_video_manage_widget"
data-live-data-value="{"video":{"title":"Dies ist ein Test","videoOnlyPresentationpageTemplate":"1ed5567e-d2bf-6a90-9bee-fd4a081f390a","_token":"bf951bf705cf7eccdb7.0m9PHUQoJcx4de_J8RRB5NvjURu1XB2zA2JmWxUuH1M.tgw_TwYfcZo3GIi5sG0jp-OCKVTyMmmLWTU-EEEYcAOCMCpVM2lKvScGug"},"isValidated":false,"validatedFields":[]}"
data-live-props-value="{"data":"1ed5ada4-e0e0-6e9e-a430-fd47a6d79fa4","editModalIsOpen":false,"shareModalIsOpen":false,"deleteModalIsOpen":false,"shareUrl":"http:\/\/127.0.0.1:8000\/v\/dxsh-2Sv3DW","doneCtaMustRedirectToOverview":false,"formName":"video","_checksum":"C8V5E5gARfsauKzyYW0nMwmGj0\/SPPRc8Me27T\/S0K8="}"
data-live-csrf-value="7.IG9PJq5-8-uWF3TKAa7KSJMwsz1IJLEs24SnT-YoNRs.FRsmQtxGvZ_vQS64YJePHdR7-nA-a9NdjeHVA7ZtVCgQQi5xwxCkjcc6Gw">
<button class="p-2 pl-4 pr-4 w-full h-full text-left text-sm" data-action="live#action"
data-action-name="showEditModal">
<span class="flex flex-row justify-between items-center gap-2">
<span>
Aufnahme bearbeiten
</span>
<span>
<svg class="h-4 w-4 text-indigo-900" xmlns="http://www.w3.org/2000/svg"
fill="currentColor" viewBox="0 0 24 24">
<path d="M21.731 2.269a2.625 2.625 0 00-3.712 0l-1.157 1.157 3.712 3.712 1.157-1.157a2.625 2.625 0 000-3.712zM19.513 8.199l-3.712-3.712-8.4 8.4a5.25 5.25 0 00-1.32 2.214l-.8 2.685a.75.75 0 00.933.933l2.685-.8a5.25 5.25 0 002.214-1.32l8.4-8.4z"></path>
<path d="M5.25 5.25a3 3 0 00-3 3v10.5a3 3 0 003 3h10.5a3 3 0 003-3V13.5a.75.75 0 00-1.5 0v5.25a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5V8.25a1.5 1.5 0 011.5-1.5h5.25a.75.75 0 000-1.5H5.25z"></path>
</svg>
</span>
</span>
</button>
</div>
To corner the problem, I have just re-created the "random number widget" by following the docs to the letter, and the result works, with the resulting DOM looking like this:
<div data-controller="live"
data-live-url-value="/_components/random_number"
data-live-data-value="{}"
data-live-props-value="{"_checksum":"IW1BQOmstmWWSSuxaDMazCkM0yGiETn4Ko\/tAYqi2HU="}"
data-live-csrf-value="377.AmS_z21vKAoM6vGl1a5VZ_JLWdKhkEdbBzYSwBUzlxU.dwHZtgAXbkxGnZnnhckFMIsTA4fo2RIvaWVhmF4E4UZ0Hc2gHQR3R2eSmg">
<strong>973</strong>
<button data-action="live#$render">Generate a new number!</button>
</div>
Ok, things look a tad better now, although it's still not back in a working state.
The "way-to-slim" POST payload was likely due to me not updating the Node dependencies via NPM (I've only now realized that I ran into another issue after doing so, not realizing that the error now lies elsewhere).
The 2.4 payload looks like this:
{
"data": "1ed5ada4-e0e0-6e9e-a430-fd47a6d79fa4",
"editModalIsOpen": false,
"shareModalIsOpen": false,
"deleteModalIsOpen": false,
"shareUrl": "http://127.0.0.1:8000/v/dxsh-2Sv3DW",
"doneCtaMustRedirectToOverview": false,
"formName": "video",
"video": {
"title": "Dies ist ein Test",
"videoOnlyPresentationpageTemplate": "1ed5567e-d2bf-6a90-9bee-fd4a081f390a",
"_token": "1c7ec31404.Kfv42Enjr35GTa1xrMIToIN-EzwXimz953CqAnOee9U.TZiIigvU-ygJIMoB7btx47sfa3NQ5BjFvSfySSeoFIV5pJ2QPqLADxk--A"
},
"isValidated": false,
"validatedFields": [],
"_checksum": "C8V5E5gARfsauKzyYW0nMwmGj0/SPPRc8Me27T/S0K8="
}
The 2.5 payload, after updating the PHP side via Composer AND the JS side via NPM, looks like this:
{
"data": {
"data": "1ed5ada4-e0e0-6e9e-a430-fd47a6d79fa4",
"editModalIsOpen": false,
"shareModalIsOpen": false,
"deleteModalIsOpen": false,
"shareUrl": "http://127.0.0.1:8000/v/dxsh-2Sv3DW",
"doneCtaMustRedirectToOverview": false,
"formName": "video",
"_checksum": "C8V5E5gARfsauKzyYW0nMwmGj0/SPPRc8Me27T/S0K8=",
"video": {
"title": "Dies ist ein Test",
"videoOnlyPresentationpageTemplate": "1ed5567e-d2bf-6a90-9bee-fd4a081f390a",
"_token": "5b8da170bb4638ed4b00e0543.uOOhAZNAoWW_jx71kKTQLVOoT8TIQjyD4EQO_cre49g.3IDRU9F39TPw4nmF0d2ybmvJN4uPLEi7uhNWtp7ojIjovMRJ5AHOFOD8Sw"
},
"isValidated": false,
"validatedFields": []
},
"childrenFingerprints": {
"live-1045461726-0": ""
},
"args": {}
}
Symfony UX on the backend handles this payload without issues and returns the updated HTML. However, now the client side runs into
Uncaught (in promise) DOMException: Failed to execute 'replaceChild' on 'Node': The node to be replaced is not a child of this node.
at http://127.0.0.1:8000/build/app.js:1350:21
at Array.forEach (<anonymous>)
at executeMorphdom (http://127.0.0.1:8000/build/app.js:1342:19)
at Component.processRerender (http://127.0.0.1:8000/build/app.js:1856:7)
at _callee2$ (http://127.0.0.1:8000/build/app.js:1810:26)
at tryCatch (http://127.0.0.1:8000/build/app.js:157:1357)
at Generator.<anonymous> (http://127.0.0.1:8000/build/app.js:157:4174)
at Generator.next (http://127.0.0.1:8000/build/app.js:157:2208)
at asyncGeneratorStep (http://127.0.0.1:8000/build/app.js:158:103)
at _next (http://127.0.0.1:8000/build/app.js:159:194)
which is triggered by https://github.com/symfony/ux/blob/ecf124f1f219135990f625903d58e79d250f7a93/src/LiveComponent/assets/dist/live_controller.js#L1197
Glad you got this much closer when you updated the deps completely. The code causing the error is, indeed, part of a whole new system from 2.5 related to child components. Do you have a child component setup - where you render a component inside of another? And is it possible that, when a parent component Re-renders, one or more of the children is removed/not present anymore (this is a valid thing to do - just trying to read into the error and find the cause)?
@weaverryan Ok, so I could solve it. The cause, however, is either rather curios, or I'm overlooking something obvious.
The problem indeed occured if one Live component contained another Live component. But only if the outermost DOM node of the "inner" Live component is not a div
.
Thus, this works:
<div
{{ attributes }}
{% if this.shouldPoll %}
data-poll
{% endif %}
>
{% if this.duration is not null %}
{{ this.duration }}
{% else %}
...
{% endif %}
</div>
while the following results in the aforementioned Failed to execute 'replaceChild' on 'Node'
error:
<span
{{ attributes }}
{% if this.shouldPoll %}
data-poll
{% endif %}
>
{% if this.duration is not null %}
{{ this.duration }}
{% else %}
...
{% endif %}
</span>
I also tried the p
, aside
, and footer
tags for good measure - nope, only div
does it. That was not the case with the 2.4 version of Live Components.
As far as I can see, neither the docs at https://symfony.com/bundles/ux-twig-component/current/index.html nor those at https://symfony.com/bundles/ux-live-component/current/index.html say anything about "allowed" or "disallowed" root DOM nodes in the templates.
However, at least the UX Twig Component docs use not only div
elements in the examples, while the UX Live Component doc examples seem to stick to only div
.
Maybe this limitation only applies for component-in-component situations?
Thanks for the clarification! It's definitely a bug - there is no limitation. But we're doing some fancy things in the latest version with the "outer tag" and child components, and apparently there is a problem with some of that. I'll check into it more deeply.
See #537 for the fix!
See https://github.com/symfony/ux/issues/537 for the fix!
That's this issue
Booo! See #593
I've just upgraded from UX
2.4.0
to2.5.0
in my Symfony6.1.7
/ PHP8.1.11
project, and all UX Live Component actions no longer work - they do trigger a POST as expected, but the backend responds with HTTP status422 Unprocessable Entity
, due to an exception thrown byLiveComponentHydrator.php:129
with messageInvalid or missing checksum. This usually means that you tried to change a property that is not writable: true.
.I've done the Composer update in isolation, i.e. nothing else changed, and it goes back to working if I do a downgrade to 2.4.0.
Here's the result of the Composer update:
When I trigger an action on version
2.4.0
, the POST payload looks like this:But when I trigger the same action on version 2.5.0, it looks a lot slimmer:
The action is simply triggered through a click on a button which looks as follows:
I've seen that there has been quite some Changed Behaviours and BCs, so maybe there are changes I need to do. Nevertheless, putting this here in case others run into the same issue.