I've tried to create dynamic nav menus by storing the menu data in a Pocketbase database, within a sveltekit store:
lib/navMenuStore.js
import { writable } from 'svelte/store';import PocketBase from 'pocketbase';const pb = new PocketBase('http://127.0.0.1:8090');export const navMenusStore = writable([]);//Fetch nav menus and pages collections in one goasync function fetchNavMenusAndPages() { try { const [navMenusRes, pagesRes] = await Promise.all([ pb.collection('nav_menus').getFullList({}), pb.collection('pages').getFullList({}) ]); // Create a map of page IDs to slugs const pageMap = pagesRes.reduce((map, page) => { map[page.id] = { slug: page.page_slug, title: page.page_title }; // Adjust with correct property names return map; }, {}); // Process each nav menu to build hierarchical structure const processedNavMenus = navMenusRes.map(menu => { return { ...menu, structuredMenu: buildMenuStructure(menu.nav_pages, pageMap) }; }); navMenusStore.set(processedNavMenus); } catch (error) { console.error("Unable to fetch nav menus and pages", error); navMenusStore.set([]); }}// Adjust buildMenuStructure to use both slug and titlefunction buildMenuStructure(menuItems, pageMap) { function findChildren(parentId) { return menuItems .filter(item => item.parent === parentId) .map(item => { const page = pageMap[item.pageId] || {}; return { ...item, slug: page.slug || '', title: page.title || 'No Title', // Use title from pageMap children: findChildren(item.pageId) }; }); } return findChildren(null).concat(findChildren(''));}export const loadNavMenusAndPages = fetchNavMenusAndPages;
/blocks/Nav.svelte
<script> import {Button} from 'flowbite-svelte'; import { navMenusStore, loadNavMenusAndPages } from '$lib/navMenuStore'; import { onMount } from 'svelte'; import { browser } from '$app/environment'; import { page } from '$app/stores'; let selectedNavMenu = null; //Imports and Exports for page builder import { getFieldConfig } from '$lib/componentConfigs'; export const configFields = getFieldConfig(['CTAButtonText']); export let CTAButtonText = ''; onMount(() => { loadNavMenusAndPages(); }); //Debugging if (browser) { onMount(() => { window.addEventListener('sveltekit:navigation-start', () => { console.log('Navigation started'); }); window.addEventListener('sveltekit:navigation-end', () => { console.log('Navigation ended'); }); }); } $: { if ($navMenusStore.length > 0 && $navMenusStore[0].structuredMenu) { selectedNavMenu = $navMenusStore[0].structuredMenu; console.log("Selected Nav Menu:", selectedNavMenu); // Debugging line } } $: console.log($page.url.pathname)</script><div class="flex bg-green-500 justify-between items-center p-8"><div><p>Text</p></div><div><Button color="yellow">{CTAButtonText}</Button></div></div><nav> {#each selectedNavMenu || [] as menuItem}<div class="group relative"><a href="/{menuItem.slug}" class="inline-block p-2 hover:bg-blue-500">{menuItem.title}</a> {#if menuItem.children && menuItem.children.length > 0}<div class="absolute hidden group-hover:block bg-white shadow-lg"> {#each menuItem.children as child}<a href="/{child.slug}" class="block p-2 hover:bg-gray-100">{child.title}</a> {/each}</div> {/if}</div> {/each}</nav>
When I click on one of the anchor tags within the loop, the URL changes but the page content isnt loaded into the DOM. It works if I add "data-sveltekit-reload" or "target="_self" within the anchor tags, but then I lose preloading for the page. I'm struggling to work out a way to achieve pre-loading while making the anchor links work.