Skip to content

Portal in examples section #4237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
frederikhors opened this issue Jan 9, 2020 · 11 comments
Open

Portal in examples section #4237

frederikhors opened this issue Jan 9, 2020 · 11 comments

Comments

@frederikhors
Copy link

Can we add this Portal repl in the examples section?

#3088 (comment)

<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.

@frederikhors
Copy link
Author

@Conduitry Conduitry added the docs label Jan 9, 2020
@PatrickG
Copy link
Member

PatrickG commented Jan 9, 2020

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>

@frederikhors
Copy link
Author

@PatrickG, You forgot onDestroy().

@PatrickG
Copy link
Member

PatrickG commented Jan 10, 2020

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>

@frederikhors
Copy link
Author

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?

@PatrickG
Copy link
Member

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}

@frederikhors
Copy link
Author

@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?

@PatrickG
Copy link
Member

It's not wrong, just another way.

@frederikhors
Copy link
Author

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.

@PatrickG
Copy link
Member

PatrickG commented Jan 10, 2020

$: 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.

@vipero07
Copy link

vipero07 commented Jan 21, 2020

<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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants