-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Fix morphing root level state #4169
Conversation
is it the reason for this bug? 3.4.10: https://wirebox.app/b/xeo72 3.4.11: https://wirebox.app/b/430dl open the modal and click on Add random |
Well, the second one there is using a much older version of Alpine. |
okay, not working in 3.4.12 too |
@MrPunyapal if it's broken in 3.4.11 (which uses Alpine 3.13.8), is not caused by this Pull request as it was only released in Alpine 3.4.10. Perhaps you can start a different discussion (maybe try the Livewire repo first). P.s. Your last link is private |
livewire/livewire#8282 (comment)
thanks updated |
Yeah, but the example you posted above uses 3.13.8 so that comment is not accurate either. Either ways, this MR is not the root cause because it was merged in a later release so it's better to open a different discussion. it will be something released between 3.13.0 working and 3.13.8 (broken). |
Solved it by tweaking some code at all the teleports |
@ekwoka and @SimoTod FYI he is talking about Livewire version numbers, not Alpine version numbers. There is a similar problem reported on Livewire that morphing is now copying across |
Yes, I did gather that. I looked at the Alpine versions used in the presented sandboxes. |
I encountered the exact same problem (on all versions of Livewire after 3.4.10). Adding a wrapper |
Thanks 👍 I solved it by adding wire.ignore.self on parent div. |
The Problem
The following HTML, when morphed to itself (like in the case of a Livewire component refreshing), will throw an error:
The error:
Uncaught ReferenceError: foo is not defined
Interestingly, the problem does NOT occur when wrapping the
x-data
element in a plain<div>
like so:The explanation
Clearly during the morph/clone phase, the live tree's
x-data
data is not being brought over to the reference<div>
during clone.Alpine's morph algorithm will walk both the live and reference tree, element by element. As it walks, it will "clone" (initialize) the reference element based on information from the live tree (such as existing
x-data
state), then compare the two, and make any "mutations" to the live tree it needs.So, in a normal, non-teleport scenario, when
<div x-data>
is encountered in the tree walk, Alpine will recognize live "state" in the live tree and graft it onto the reference tree before initializing the reference element (cloning).However, for some reason Alpine isn't carrying over the "live" state from the live tree to the reference tree when
x-data
is the first child ofx-teleport
.Here's the reason this is happening:
As Alpine walks both trees during morph, when it encounters an element using
x-teleport
, it will internally do it's own "teleport" in the DOM from the<template>
element to the live, teleported element.To understand the problem, you have to understand two key processes in "morph":
patch
andpatchChildren
patch(from, to)
operationpatchChildren(from, to)
(recursively patch each child)patchChildren(from, to)
operation<template>
tag's children.patch()
, remove, and add elementsAs you can see from above, the combination of
patch()
andpatchChildren
, is how morph crawls a both DOM trees in parallel.The problem is that the
teleported
elements are substituted until AFTER the<template>
elements are cloned. This means that the<div x-data>
elements never have an opportunity to be "cloned", and the state is never grafted over, resulting in state-based scope errors downstream.The solution
Solution A: Re-clone template targets
We could call "clone" once more inside
patchChilren()
when the "from" and "to" are about to be substituted with their actual teleported elements.Pros:
Cons:
Solution B: Re-run
patch()
on targetsFrom inside
patchChildren()
, we could pass the template target elements back throughpatch()
and return early.Pros:
Cons:
Solution C: Swap teleport targets earlier
We could also move the conditional for swapping teleport targets earlier in the process (out of
patch()
and intopatchChildren
).Pros
Cons
<template>
element and which apply to the<div>
elements (swapping, cloning, lifecycle hooks, etc...)<template>
AND<div>
to be cloned so there would need to be duplication somewhereSolution D: Just graft state
Instead of full on "patching" the teleport targets, we could just move state if it exists over to the "to" tree.
Pros:
Cons:
Based on the above, I think solution "B" is worth trying, as it's the most comprehensive. It is also the scariest to me (risk of causing other complicated bugs), but we should at least try it.