Skip to content

Commit

Permalink
fix skipped children on stream reset (#3070)
Browse files Browse the repository at this point in the history
When fixing stream limits I added a component restore functionality,
but this was only working with LiveComponent that were skipped and only
if they were the direct stream children. It could still happen that
nested elements inside the stream child were skipped and not restored.

This commit solves this by storing all stream child elements children
with a PHX_MAGIC_ID and restoring them later in case they were skipped.

Co-authored-by: Steffen Deusch <steffen.deusch@teaminternet.com>
  • Loading branch information
SteffenDE and Steffen Deusch committed Feb 1, 2024
1 parent 3aab8ae commit 1a75fe6
Showing 1 changed file with 12 additions and 11 deletions.
23 changes: 12 additions & 11 deletions assets/js/phoenix_live_view/dom_patch.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,13 @@ export default class DOMPatch {

DOM.putSticky(child, PHX_STREAM_REF, el => el.setAttribute(PHX_STREAM_REF, ref))

// we may need to restore the component, see removeStreamChildElement
if(child.getAttribute(PHX_COMPONENT)){
if(child.getAttribute(PHX_SKIP) !== null){
child = this.streamComponentRestore[child.id]
} else {
delete this.streamComponentRestore[child.id]
// we may need to restore skipped components, see removeStreamChildElement
child.querySelectorAll(`[${PHX_MAGIC_ID}][${PHX_SKIP}]`).forEach(el => {
const component = this.streamComponentRestore[el.getAttribute(PHX_MAGIC_ID)]
if(component){
el.replaceWith(component)
}
}
})

// streaming
if(streamAt === 0){
Expand Down Expand Up @@ -328,10 +327,12 @@ export default class DOMPatch {

removeStreamChildElement(child){
if(!this.maybePendingRemove(child)){
if(child.getAttribute(PHX_COMPONENT) && this.streamInserts[child.id]){
// live component would be removed and then be re-added;
// because of the PHX_SKIP optimization we need to temporarily store the DOM node
this.streamComponentRestore[child.id] = child
if(this.streamInserts[child.id]){
// we need to store children so we can restore them later
// in case they are skipped
child.querySelectorAll(`[${PHX_MAGIC_ID}]`).forEach(el => {
this.streamComponentRestore[el.getAttribute(PHX_MAGIC_ID)] = el
})
}
child.remove()
this.onNodeDiscarded(child)
Expand Down

0 comments on commit 1a75fe6

Please sign in to comment.