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?
CodePudding user response:
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
});
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`
}
}