Search code examples
storesveltesappersvelte-3

Svelte access a store variable in child component script tag


I have a Svelte & Sapper app where I am using a Svelte writable store to set up a variable with an initial blank string value:

import { writable } from 'svelte/store';
export let dbLeaveYear = writable('');

In my Index.svelte file I am importing this and then working out the value of this variable and setting it (I am doing this within the onMount function of ```Index.svelte if this is relevant):

<script>
  import {dbLeaveYear} from "../stores/store.js"

  function getCurrentLeaveYear() {
    const today = new Date();
    const currYear = today.getFullYear();
    const twoDigitYear = currYear.toString().slice(-2);
    const cutoffDate = `${twoDigitYear}-04-01`
    const result = compareAsc(today, new Date(cutoffDate));
    if (result === -1) {
      $dbLeaveYear = `${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`;
    } else {
      $dbLeaveYear = `${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`;
    }
  }

  onMount(() => {
    getCurrentLeaveYear();
  });
</script>

I have a child component being rendered in the Index.svelte

<Calendar />

Inside the Calendar child component I am importing the variable and trying to access it to perform a transform on it but I am getting errors that it is still blank - it is seemingly not picking up the assignment from Index.svelte:

<script>
  import {dbLeaveYear} from "../stores/store.js"
  const calStart = $dbLeaveYear.slice(0, 2)
</script>

However if I use the value in an HTML element in the same Calendar child component with <p>{$dbLeaveYear}</p> it is populated with the value from the calculation in Index.svelte.

How can I access the store variable inside the <script> tag of the child component? Is this even possible? I've tried assiging in onMount, I've tried assigning in a function - nothing seems to work and it always says that $dbLeaveYear is a blank string.

I need the value to be dynamic as the leave year value can change.


Solution

  • The answer here is a combination of Sapper preload and the ability to export a function from a store.

    in store.js export the writable store for the variable you want and also a function that will work out the value and set the writable store:

    export let dbLeaveYear = writable('');
    
    export function getCurrentLeaveYear() {
      const today = new Date();
      const currYear = today.getFullYear();
      const twoDigitYear = currYear.toString().slice(-2);
      const cutoffDate = `${twoDigitYear}-04-01`
      const result = compareAsc(today, new Date(cutoffDate));
      if (result === -1) {
        dbLeaveYear.set(`${parseInt(twoDigitYear, 10) - 1}${twoDigitYear}`);
      } else {
        dbLeaveYear.set(`${twoDigitYear}${parseInt(twoDigitYear, 10) + 1}`);
      }
    }
    

    In the top-level .svelte file, use Sapper's preload() function inside a "module" script tag to call the function that will work out the value and set the writable store:

    <script context="module">
      import {getCurrentLeaveYear} from '../stores/store'
      export async function preload() {
            getCurrentLeaveYear();
      }
    </script>
    

    And then in the component .svelte file, you can import the store variable and because it has been preloaded it will be available in the <script> tag:

    <script>
      import {dbLeaveYear} from '../stores/store'
    
      $: startDate = `20${$dbLeaveYear.slice(0, 2)}`
      $: endDate = `20${$dbLeaveYear.slice(-2)}`
    </script>