typescriptsveltesveltekit

How to get the value of a streamed promise outside the scope of its await block in SvelteKit?


I have a +layout.server.ts that performs an API request and returns the data to its sibling +layout.svelte. Since this request can take a second or two, it's value is inside an await block in my Svelte code so I can display a loading indicator.

This all works fine, however I am now trying to set the title of the page to a value contained in the resolved promise and am hitting a wall. I cannot place await blocks in the <title> tag and I cannot modify state from within Svelte code directly so is there a possible way of achieving this?

My code for reference: +layout.server.ts:

import type { LayoutServerLoad } from "./$types";
import { getPlayer } from "$lib/utils";

export const load: LayoutServerLoad = async ({ params }) => {
    return {
        streamed: {
            player: getPlayer(params.username)
        }
    };
}

+layout.svelte (this is where I am hitting the wall the wall)

<script lang="ts">
    import Header from "$lib/blocks/Header.svelte";
    import type { LayoutProps } from "./$types";
    let { data, children }: LayoutProps = $props();

    let title = $state("Loading...");
    function setTitle(newTitle: string) { title = newTitle; console.log(newTitle); }
</script>

<svelte:head>
    <title>{title}</title>
</svelte:head>
<div>
    <Header />

    <div>
        {#await data.streamed.player}
            <p>Loading...</p>
        {:then player}
            {setTitle(player?.username || "Player not found!")}
            <p>{player?.username}</p>
        {:catch error}
            {setTitle("Player not found!")}
            <p>Problem loading player data!</p>
        {/await}
    </div>

    {@render children()}
</div>

Solution

  • I might have misunderstood, but can't you simple use {#await} two times on the same promise?

    <svelte:head>
        {#await data.streamed.player}
            <title>Loading...</title>
        {:then player}
            <title>{player?.username ?? "Player not found!"}</title>
        {:catch error}
            <title>Player not found!</title>
        {/await}
    </svelte:head>
    
    <div>
        <Header />
    
        <div>
            {#await data.streamed.player}
                <p>Loading...</p>
            {:then player}
                <p>{player?.username}</p>
            {:catch error}
                <p>Problem loading player data!</p>
            {/await}
        </div>
    
        {@render children()}
    </div>