This is a super bizarre error. Seems like it happens semi randomly. I was able to narrow it down to a reproducible example. Hopefully you guys can get more from this than I.
Changes to data and rerendering should not orphan elements and fail to delete them.
Changes to data and rerendering sometimes (seemingly randomly) fails to delete elements.
Throws either TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'. or TypeError: Cannot read property 'parentNode' of null
https://stackblitz.com/edit/js-mennea
The project has a working example. To see behavior, open the console and click the 'Regenerate x1000' button. Errors will randomly happen.
As the example alludes to I have a tree of folder-like things that I want to display in a tree structure. Based on navigation, I want to be able to show a parent folder with child subfolders, then open one of the subfolders and view it as root. (Generic file system.)
After playing with this more, it seems like these errors go away if you remove the uncertanty.
The first block causing problems is fixed if you always insert a node in it's spot.
This ...
if (item.children)
output.push(
m('.child', item.children ? generateItems(item.children) : ''),
)
... becomes ...
output.push(
m('.child', item.children ? generateItems(item.children) : ''),
)
... or ...
output.push(
item.children ? m('.child', generateItems(item.children)) : null
)
The second block is fixed if you insert a mithril element instead of an unknown number of items.
This ...
output.push(
someSizedArray.map((item, index) => m('.row', 'some row'))
)
... becomes ...
output.push(
m('', someSizedArray.map((item, index) => m('.row', 'some row')))
)
Still not sure what causes this in the first place.
I'm facing the same issue (using v1.1.6) and finally was able to track it down. See fiddle: http://jsfiddle.net/tokafew420/e6w8txLd/4/
To reproduce the issue, just step through the example.
The problem arises in a very specific scenario and chain of events. I just started digging through the code so I'm not too familiar with it but I'll try to explain what I think is happening in my example.
Required state:
Steps in example:
old.dom (which is now the same reference as vnode.dom because of the recycling), and append it to parent. This puts the element at the bottom of the list. mithril.js:816 Uncaught TypeError: Cannot read property 'parentNode' of null
at removeNodeFromDOM (mithril.js:816)
at continuation (mithril.js:803)
at removeNode (mithril.js:794)
at removeNodes (mithril.js:774)
at updateNodes (mithril.js:607)
at updateFragment (mithril.js:653)
at updateNode (mithril.js:628)
at updateNodes (mithril.js:537)
at updateElement (mithril.js:687)
at updateNode (mithril.js:629)
This is because the vnode.dom is assumed to be the first-child and the removal process uses this assumption and traverses the nextSibling property to remove all children of the parent. Unfortunately since the node is moved to the last-child position, the nextSibling property is null. Hence the error.
Now, the question is...how do I fix this?
@MynockSpit thanks for the report, somehow I let this one slip, sorry.
@tokafew420 thanks for the repro and analysis.
This was probably fixed in next (the pool was heavily reworked) before we decided to shelve the pool altogether for v2.
As a workaround, you can opt out of the pool by setting a hook on the fragment such as oncreate or onupdate on the children of the fragment. There's no other way to opt out of it.
This is like #1991 , was fixed in next.
Thanks for the response @pygy
I was able to work-around the issue by wrapping the children array. This work-around also fixed the issue in @MynockSpit 's example. I simply changed line 53 in his example from
return output;
to
return m('', output);
I saw that adding a hook will opt out of the pool but when returning arrays it's difficult to add the hook inline.
Looking forward to next.
@tokafew420 For hooks on fragments, you can use m.fragment({oncreate(){}}, [...children]}). m('', ...) adds a wrapping div.
See here for @MynockSpit's example updated accordingly.
Thanks for the insight. I totally skimmed pass that section. Lol