Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a component that is aware of the current url in Sapper with Svelte?

Tags:

svelte

sapper

I have a page that has a nav bar with a "Quarters" link. Under the Quarters link, when the user is on the /quarters route, a list of quarters will be shown, like 2019Q2 etc. The url will be /quarters/2019q2.

I want to make a component that show shows a hyperlink that will have the selected class if the current url matches the href of the link. Here's the closest I can get:

<script>
  import { afterUpdate } from 'svelte';
  export let segment;
  export let text = 'text here';
  export let link;
  let isCurrentPath = false;
  console.log(segment, link, text);
  afterUpdate(() => {
    if (window.location.pathname.includes(link)) {
      isCurrentPath = true;
      debugger;
    }
    console.log('HL afterUpdate ', window.location);
  });
</script>

<style>
  /* omitted */
</style>

<a class:selected={segment && isCurrentPath} href={link}>{text}</a>

That works fine for the first load, but when the user navigates to a different data page the selection is not updated. How do I get some code to only run on the client-side? If I access the window object outside of afterUpdate I will get an null ref error from the server-side code.

ETA: Tried this too:

  let isCurrentPath = false;
  let path = typeof window === 'undefined' ? '' : window.location.pathname;
  $: if (path) isCurrentPath = window.location.pathname.includes(link);

That code doesn't fire when the user clicks one of the data links. Tried onMount as well with no positive result.

like image 821
jcollum Avatar asked Sep 05 '19 21:09

jcollum


2 Answers

For people using SvelteKit, the given answers still apply. Take a look at the docs for the page store: https://kit.svelte.dev/docs/modules#$app-stores-page

EDIT: There were breaking changes in a new SvelteKit update. You still access the current url from the page store like this:

import { page } from '$app/stores';
$page.url.pathname
like image 166
m1212e Avatar answered Nov 09 '22 19:11

m1212e


The trick is to create a reactive statement based on a value in the page store.

<!--
This is used to have a link on the page that will show highlighted if the url meets the criteria.
You might want to adjust the logic on line 19.
usage: 
<HighlightedLink bind:segment highlight="faq" rel="prefetch" link="/faq" text="FAQ" />
--> 

<script>
  import { stores } from '@sapper/app';
  const { page } = stores();
  export let highlight;
  export let segment;
  export let text = 'text here';
  export let link;
  export let target;
  let highlightPath = false;
  $: highlightPath =
    $page.path && highlight && ($page.path.includes(highlight) || $page.path.includes(link));
</script>

<style>
  .selected {
    position: relative;
    display: inline-block;
  }
  .selected::after {
    position: absolute;
    content: '';
    width: calc(100% - 1em);
    height: 2px;
    background-color: rgb(255, 62, 0);
    display: block;
    bottom: -1px;
  }
  a {
    padding-left: 10px;
  }
</style>


<a class:selected={highlightPath} href={link}>{text}</a>
like image 10
jcollum Avatar answered Nov 09 '22 21:11

jcollum