I have one component that should conditionally wrap another component (one it's an app, the other is something like a mockup for better visuals).
I was initializing them like:
const appContainer = document.createElement('DIV')
new App({ target: appContainer })
new POS({
target: root,
slots: {
default: appContainer,
},
})
And started receiving the error: Failed to execute 'appendChild' on 'Node': The new child element contains the parent.
However, if you replace the createElement with a createDocumentFragment it works 100%.
createElement also works when removing the if condition in the Machine.html
@plumpNation Yeah, but the if in my real scenario is needed (I've simplified it a lot in the REPL) 馃榿
Maybe it could be a clue for someone with good Svelte source code knowledge?
Svelte components are not constrained to being wrapped by a root element.
Also, you can send a group of elements into a slot, instead of having to wrap them up in a parent element.
Therefore slots expect a fragment instead of an element.
I think this is one of the side effects of not having the constraint to wrap everything in a parent element.
If you instantiated machine.html declaratively (_instead of programmatically as you have done_), you would notice that the compiled code for app.html will contain a call to createFragment when instantiating machine.html internally.
I found that removing the {:else} also allowed it to work. I'm not sure how relevant that is now after @ekhaled's explanation. I am aware that the OP requires the if and the else, I just thought it was interesting.
Programmatic slots are not a public api.
Svelte uses either appendNode or insertNode depending on whether it has to render slot content conditionally.
In OP's case... if you set the condition to be true to start with (in Machine.html's data), you will notice that it works perfectly.
Fortunately, using a fragment works for both insertNode and appendNode
@ekhaled I see! Thank you so much for your insights 馃榿