Loosing DOM state when prepending element
Environment
- morphdom version: 2.6.1
- Browser: Safari 13.1.1 / Chrome 83.0.4103.116
Expected behavior
Calling morphdom to prepend a element to the container should keep the previous active input element focus
Actual behavior
The browser state and input focus is lost
Reproduce
I tried adding an ID to every element, even the newly introduced element.
https://jsfiddle.net/kajr2zmv/
All console.log statements expected to be true
"isActive control", true
"isActive appendEl", true
"isActive control", true
"isActive prependEl", false
FWIW, I originally stumbled across this as my element scroll position was getting lost. The input focus is just a smaller use-case easier to test against
While replacing an existing DOM tree with an entirely new DOM tree will actually be very fast, it comes with a cost. The cost is that all of the internal state associated with the existing DOM nodes (scroll positions, input caret positions, CSS transition states, etc.) will be lost
This is extremely misleading as the morphdom algorithm comes with this same cost. I couldn't find a version without this behavior. It appears to build down to the use of appendChild
You'll find a lot of the diffing algorithms have the same problem with prepending to the tree.
Curious though if this is on the roadmap to fix?
@tropperstyle I'd have to take a deep look at this. As you mentioned, once we detect a change, we throw a grenade at the siblings and children. However, if they exist in cache by id, we stitch them back together. This seems to still lose the focus state.
I'm not sure of a good solution yet. Seems like we would have to keep a cache of focused state around and add that that back to the DOM after we have traversed the tree. Surely something that would be nice for this library to handle. Just not sure of a good solution...
FWIW, I originally stumbled across this as my element scroll position was getting lost. The input focus is just a smaller use-case easier to test against
So, tracking focus explicitly wouldn't have helped in my case as I discovered this issue after loosing scrollTop. There might be other "stateful" properties I'm not aware of off the top of my head
Hey @snewcomer,
I've been trying to find a solution to this problem for several days. It cuts deeper than just focus and scroll state.
We're finding that if you insert a new sibling, two additional problems emerge when you "grenade" siblings.
- The
onBeforeElUpdatedcallback is not considered, so any attempts to preserve a sibling (we use at attribute to mark elements as protected from morphing) are silently ignored. - The internal state of an iframe is reloaded due to being detached and reattached from the DOM.
I'm willing to PR this but I feel like I'm a bit under water trying to figure out how to attack this. I've been trying to figure out a way to get siblings enumerated in handleNodeAdded and into the It seems like instead of doing the fromNodesLookup object. I am just breaking it, though, and after three days, I have to send up the white flag.
Is this on your horizon, Scott? Do you have any idea how to best go about implementing this functionality?