Can we add this Portal repl in the examples section?
https://github.com/sveltejs/svelte/issues/3088#issuecomment-505785516
<script>
// src/components/Portal.svelte
import { onMount, onDestroy } from 'svelte'
let ref
let portal
onMount(() => {
portal = document.createElement('div')
portal.className = 'portal'
document.body.appendChild(portal)
portal.appendChild(ref)
})
onDestroy(() => {
document.body.removeChild(portal)
})
</script>
<div class="portal-clone">
<div bind:this={ref}>
<slot></slot>
</div>
</div>
<style>
.portal-clone { display: none; }
</style>
Copyright @ThomasJuster.
Could be a bit simpler
<script>
import { onMount } from 'svelte';
let ref;
onMount(() => document.body.appendChild(ref));
</script>
<div class="portal" bind:this={ref}>
<slot></slot>
</div>
@PatrickG, You forgot onDestroy().
You don't need the onDestroy. Svelte removes the element anyway.
You can event do it like that:
<script>
let ref;
$: ref && document.body.appendChild(ref);
</script>
<div class="portal" bind:this={ref}>
<slot></slot>
</div>
Ok. And what If I need to "append" it not on body but in another component?
For example in <Sidebar /> already in App.svelte?
I'm using the id with document.getElementById("sidebar") right now but I'm wondering if there is a better way.
And sometimes (based on routing or custom logic, maybe behind a Svelte if false) the sidebar div is not present on the page, so it's a problem.
I opened this issue to address this "situation" "the right way".
Your hint?
That's not the right place to ask this kind of questions, you should discuss this on discord.
You could do something like this
<script>
// App.svelte
import Whatever from './Whatever.svelte';
import Sidebar from './Sidebar.svelte';
</script>
<Sidebar Child={Whatever} />
<script>
// Sidebar.svelte
export Child = undefined;
</script>
{#if Child}
<Child />
{/if}
@PatrickG this is not what I'm asking, but it's ok.
Talking about the onDestroy question, see here: https://github.com/romkor/svelte-portal/blob/master/src/Portal.svelte#L16-L18.
The guy here is using the onDestroy.
Is it wrong?
It's not wrong, just another way.
There's a typo in your code, a double ) in ...appendChild(ref));.
Can you explain it better the magic of this line?
$: ref && document.body.appendChild(ref);
I can open a PR for this example with your amazing code.
$: means it's a reactive statement.
As soon as the value of ref changes, it gets executed.
ref && ... is the same as if (ref) { ... }
You better ask such questions on discord.
<script> let ref; $: ref && document.body.appendChild(ref); </script> <div class="portal" bind:this={ref}> <slot></slot> </div>
This should absolutely be in the svelte examples.
https://svelte.dev/repl/48afb902e70a4349bd0bfbe69d514df1?version=3.17.2 here is a repl
Most helpful comment
You don't need the onDestroy. Svelte removes the element anyway.
You can event do it like that: