How to change +layout.svelte component on page navigation in svelte?
Asked Answered
M

1

6

I am new to svelte so I cannot figure this out how to solve this after many tries. Imagine I have a component Navbar.svelte in the $lib/component. As usual I will add this component to my +layout.svelte file. What I am trying to do is make this Navbar dynamic so that the content of the Navbar changes according to my page.

The idea comes from Dynamic Island (Apple iPhone) and I want a navbar that is always stays on top and responsive like that.

(This is one of the reasons why I put my <Navbar/> in +layout.svelte because I will be using page transitions and I don't want the navbar to be a part of the page transition, it will stay on top always visible) Here is an example taken from my project.

File: Navbar.svelte

<nav> 
    <slot> 
        <a href="/another-page"> Another Page </a> 
        <h1> This is navbar for home </h1> 
    </slot> 
</nav 

File: +layout.svelte

<script> // imports </script> 
<Navbar/> 
<slot/> 
<Footer/> 

File: +page.svelte

<h1> This is a Home page </h1> 

How can I change the navbar when I click on the /another-page link so that in /another-page my navbar will contain only these:

<a href="/"> Home </a> 
<h1> This is navbar for Another Page </h1> 

I tried named slots but it seems like +layout.svelte only accepts one slot.

Misbeliever answered 23/9, 2023 at 1:47 Comment(0)
O
11

One way to do this is to use a Svelte store to pass around the constructor of the navbar component you want. You can see a live demo here.

Explanation

We use <svelte:component> in the routes/+layout.svelte file and bind that component to a simple writable store named currentNavBar.

We then create 2 navbar components: HomeNavBar and AnotherPageNavBar.

Then, in routes/+page.svelte, we set the store value to be the constructor of HomeNavBar. We also do the equivalent needful in routes/anotherpage/+page.svelte.

This is routes/+layout.svelte:

<script>
    import './global.css';
    import currentNavBar from '../stores/currentNavBar.js';
</script>

<!-- UPDATE 2024-07-04:  Wrap with an IF block in case no navbar is needed. -->
{#if $currentNavBar}
    <svelte:component this={$currentNavBar} />
{/if}

<slot />

This is stores/currentNavBar.js:

import { writable } from 'svelte/store';

export default writable(undefined);

This is routes/+page.svelte, the homepage, the script part:

<script>
    import HomeNavBar from '$lib/NavBars/HomeNavBar.svelte';
    import currentNavbar from '../stores/currentNavBar.js';

    export let data;

    $currentNavbar = HomeNavBar;
</script>

This is routes/anotherpage/+page.svelte:

<script>
    import AnotherPageNavBar from '$lib/NavBars/AnotherPageNavBar.svelte';
    import currentNavBar from '../../stores/currentNavBar.js';

    $currentNavBar = AnotherPageNavBar;
</script>

<h1>This is Another Page</h1>
Overhang answered 23/9, 2023 at 8:4 Comment(2)
Couple of notes: - I have to initialize store without undefined value - in a way: export default writable(), otherwise I got error 'Type 'typeof HomeNavBar__SvelteComponent_' is not assignable to type 'undefined'' when $currentNavbar = HomeNavBar; - when I go to any page that not suppose to have navbar, I ough to clean it, otherwise there will be ...PageNavBar from last navigated component that suppose to have one Me also new to svelte, and notes above makes me think if @José solution is cleanest and properest one. But at leest it's best I found yet, so huge thanks anywayCodicodices
@BankAngle just wrap the <svelte:component> element around an IF so you don't get an error. I'll update the answer.Gentle

© 2022 - 2024 — McMap. All rights reserved.