Skip to content
Advertisement

How to return a derived function that use fetched data from db based on value of another writable value in svelte/svelte kit?

I am trying to get my language table’s data from db in store.js and modify that data based on the language user selected. So the selected language is a writable variable and I need to get a derived function that returns the modified data. Here is my code in store.js

import { writable, derived } from 'svelte/store'; 

export async function getData(endpoint){
    try {
        const res = await axios.get(`${baseAPI}${endpoint}`);
        return res.data;
    } catch (e) {
        return e;
    }
}
function getTypography(lang){
    let typography;
    try {
        const texts = getData('/language');
        texts.then((data)=>{
            typography = data.payload;
            console.log(typography);
            return filterTypography(typography, lang)
        }).catch((e)=>{
            console.log('error', e);
        })        
    } catch (error) {
        console.log('error', error);
    }
}

function filterTypography(typography, lang){
    let textarray=[];
    typography.forEach((element, index) => {
        textarray[index]={
            'keyword':element.keyword,
            'value':element[lang]
        }
    });
    return textarray
}

export const key = writable('en')
export const updateKey = (lang) => {
    key.set(lang)
}
export const data = derived(key, $key => getTypography($key));

Here is the code in my +page.svelte

<script>
    import { key, data, updateKey } from '$lib/store.js'
    
    function changeLang(lang){
        console.log("clicked with", lang);
        updateKey(lang)
    }
   
    $: console.log($key)
</script>

<h1>{$data}</h1>
<button  on:click={() => changeLang('dk')} >Change to DK</button>
<button  on:click={() => changeLang('en')}>Change to EN</button>

I am getting ‘undefined’ data. I am just trying to print out the data variable for testing. Please note that, the console log that I am printing after getting the data from the API endpoint is showing the data successfully. Also, another thing, if I just use a function in store instead of the getTypography function, that returns different static array based on the language chosen, it works perfectly fine. So to my understanding the issue might be getting the data properly from db. What can I do here?

Advertisement

Answer

The derived store makes no sense in this context because the data is updated asynchronously. The problem being that getTypography is not returning anything, but being used in data as if that were the case.

Just make data a writable and update that when the language changes. I.e. use something like:

key.subscribe($key => updateData($key))

Where the updateData function is analogous to getTypography but sets the data store.

Something like:

const data = writable([]);
async function updateData(lang) {
    try {
        const languageData = await getData('/language');
        const typography = languageData.payload;

        data.set(filterTypography(typography, lang));
    }
    catch (error) {
        console.log('error', error);
    }
}

(You may want to add additional logic to invalidate previous requests to prevent race conditions.)


If data for all languages is requested at once, you can update a base store asynchronously and use a derived store just for the filtering. It should be based on both the language (key) and the store that is updated with all the language data.

An example of the principle:

import { writable, derived } from 'svelte/store';

const key = writable('en');
const allData = writable({});
const data = derived([allData, key], ([$allData, $key]) => {
    return $allData[$key]; // Filter data based on language
});

REPL


You could also rewrite getTypography to actually return the promise it creates internally, but then you would have to use something like {#await} everywhere you use data.

async function getTypography(lang) {
    try {
        const data = await getData('/language');
        const typography = data.payload;

        return filterTypography(typography, lang);
    }
    catch (error) {
        console.log('error', error);
        // If you do not return anything here, the awaited store will be `undefined`
    }
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement