m40ma0
m40ma0

Reputation: 45

SvelteKit routing for components

I have a left section containing a mini navbar (buttons: users, create, coins) and a right section containing the content I want to display (display coins section when coins button is clicked, ...)

However currently, the routing I want to achieve is not what I want at the moment.

When for example, the users button is clicked, I want the routing/url to be shown as settings/users, rather than just settings, settings/create for the create button and settings/coins for the coins button.

The following is the code: settings/+page.svelte

<script>
    import { page } from '$app/stores'
    import Create from './create/+page.svelte'
    import Users from './users/+page.svelte'
    import Coins from "./coins/+page.svelte"

    export let data
    let loading = false
    let currentSetting = 'create'
    $: currentSetting = $page.url.hash?.substring(1) || 'create';
</script>

<div class="flex mt-5 h-full">
    <!-- Left section -->
    <div class="flex flex-col items-center gap-4 w-44"> 
        <a href="#create" on:click={()=>{currentSetting='create'}} class="w-full btn btn-ghost         {currentSetting==='create' ? 'btn-active':''}">Create</a>
        <a href="#users" on:click={()=>{currentSetting='users'}} class="w-full btn btn-ghost {currentSetting==='users' ? 'btn-active':''}">Users</a>
        <a href="#coins" on:click={()=>{currentSetting='coins'}} class="w-full btn btn-ghost {currentSetting==='coins' ? 'btn-active':''}">Coins</a>
    </div>
    <div class="divider divider-horizontal"></div>

    <!-- Right section -->
    <div class="flex-1">
        {#if currentSetting==='create'}
            <Create categories={data?.categories}/>
        {:else if currentSetting==='users'}
            <Users bind:loading={loading} users={data.allUsers}/>
        {:else if currentSetting==='coins'}
            <Coins bind:loading={loading} users={data.allUsers}/>
        {/if}
    </div> 
</div>

where coins, create and users are all components in settings/coins/+page.svelte, settings/create/+page.svelte and settings/users/+page.svelte respectively.

When a button is clicked, currentSetting changes such that the display changes to the correct display (users button clicked, displays users settings.

I have tried using a pseudo route for each component, but I do not want to use it as it cannot have its own +page.server.js.

Thus, changing the link of a anchor tag is needed.

I was thinking of using slug, but I'm unsure of how to actually use it.

Upvotes: 2

Views: 1760

Answers (1)

Thomas Hennes
Thomas Hennes

Reputation: 9979

I believe you are confusing pages and components.

In SvelteKit, pages are placed under /src/routes/ in a hierarchy that mirrors your desired URL paths to access each page. SvelteKit will then infer the routing from that /src/routes/ directory structure. This is where you will define +page.svelte, +page.js, etc. files for page declarations, +layout.svelte etc. files for layouts, +server.js files for endpoints, etc.

You do not need to import pages in order to link to them, you simply use the standard HTML <a href="...">...</a> tag with the correct URL to reach the page you want linked to. For instance, a page declared as /src/routes/settings/users/+page.svelte will be, by convention, accessible on your site at yoursite.com/settings/users and can be linked to with <a href="/settings/users">Users</a>.

You can read about SvelteKit routing in detail here.

In addition to pages, you can also create components, which are like reusable building blocks for your pages. These are typically placed under /src/lib/ and have names like MyForm.svelte. These components will have to be imported in your page files before you can use them there.

You can find a typical SvelteKit project structure here.

Complementary information: using layouts

Layouts are part of the /src/routes tree and help define common structural elements shared by several pages.

Layouts usually apply to all the pages that are located below them in the /src/routes/ directory hierarchy, although there are special mechanisms available to escape individual page files from using layout(s) that would normally apply to them.

Layouts can be nested. In your particular use case, for instance, you would want to locate your side navigation in /src/routes/settings/+layout.svelte. This is what it that file would look like:

// /src/routes/settings/+layout.svelte

<script>
  export let data; // from the layout's load() function, see further below
  $: current = data.route.id
</script>

<div class="flex mt-5 h-full">
    <!-- Left section -->
    <div class="flex flex-col items-center gap-4 w-44"> 
        <a href="/settings/create" class="w-full btn btn-ghost {current === '/settings/create' ? 'btn-active':''}">Create</a>
        <a href="/settings/users" class="w-full btn btn-ghost {current === '/settings/users' ? 'btn-active':''}">Users</a>
        <a href="/settings/coins" class="w-full btn btn-ghost {current === '/settings/coins' ? 'btn-active':''}">Coins</a>
    </div>
    <div class="divider divider-horizontal"></div>

    <!-- Right section goes here -->
    <div class="flex-1">
      <slot></slot>
    </div> 
</div>

And the accompanying /src/routes/settings/+layout.js:

// /src/routes/settings/+layout.js
export function load({ route }) {
  return { route };
}

The above load function will simply get the name of the route from the incoming request and pass it on to the layout (and its child pages). You need this in order to properly set the btn-active class in your side navigation for the currently active page.

With the layout defined above, any pages declared under /src/routes/settings/ will apply this layout and be loaded into the <slot></slot> declared in the layout.

You can read more about SvelteKit layouts here.

Note that all of this is really the A-B-C of SvelteKit. I urge you to go back to the docs to get a solid grasp of a SvelteKit project structure and a thorough understanding of its routing/page structure conventions.

Upvotes: 5

Related Questions