I am trying to use a Svelte datastore and a Restapi backend to store, display and update a simple list of objects.
The front end has a table of items, a text entry, and a button to add to the list.
When I add to the list the datastore seems to update okay, as does the backend JSON.
The table in the frontend however only display "undefined" until the page is refreshed manually in the browser.
The logic I have tried to use is as follows: The App function handleAddItem() triggers the function addData() on the custom store and then it does an update on the items = [...items, new_data].
Table shows undefined until the page is refreshed
Any clues what I might be doing wrong?
api.js backend server
export async function fetchData(){
console.log("fetching data");
const response = await fetch("http://localhost:3000/data")
const data = await response.json();
return data
}
export async function addItem(item_label){
console.log("Backend api is posting item: ", item_label);
const newlyAddedItem = {item_label};
const settings = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(newlyAddedItem)
};
try {
const url = `http://localhost:3000/data`;
const response = await fetch(url, settings);
const newlyAddedItem = await response.json();
console.log("returned data after POST", newlyAddedItem)
} catch (e) {
return e;
}
}
datastore.ts
import { writable } from "svelte/store";
import { fetchData, addItem } from "../backend/api.js";
import type item from "../../src/App.svelte";
function alistStore() {
const { subscribe, update, set } = writable([])
return {
subscribe,
update,
loadData: async () => {
let data = await fetchData();
set(data);
return data
},
addData: async (item_label) => {
console.log("Datastore handling add item: ", item_label)
let new_data: item = await addItem(item_label);
return new_data
}
};
}
export let alist_store = alistStore();
App.svelte
<script lang="ts">
import { alist_store } from "./stores/datastore";
import { onMount } from "svelte";
interface item {
"id": number,
"item_label": string
};
export let items: item[];
export let new_data;
export let item_label = "";
alist_store.subscribe((data) => items = data)
onMount(() => {
alist_store.loadData();
})
async function handleAddItem(item_label) {
console.log("App is handling add item: ", item_label);
new_data = alist_store.addData(item_label);
console.log("updating items")
items = [...items, new_data];
console.log("updated items")
};
</script>
<main>
<table>
<th>Id</th>
<th>Name</th>
{#each items as item (item.id)}
<tr>
<td>{item.id}</td>
<td>{item.item_label}</td>
</tr>
{/each}
</table>
<div>
<textarea bind:value={item_label}></textarea>
<button on:click={() => handleAddItem(item_label)}></button>
</div>
</main>
I have tried a few things:
1: reloading the data from the store
2: trying to add reactive syntax to the => $items
3: I tried defining the object type as "item" before adding it to the list.
I think it might be to do with how things are being handled by the async and await, but this is all new to me - so I am left a bit confused.....
It looks like a problem with the order in things are happening??
CodePudding user response:
There's the log console.log("returned data after POST", newlyAddedItem)
at the end of addItem
inside api.js
but newlyAddedItem
isn't returned
alist_store.addData
is async -> new_data = await alist_store.addData(item_label);
(if the variable new_data
is only needed inside this function it wouldn't have to be declared on top level)
CodePudding user response:
Change the function on the addAlbum in the datastore.
It needed to handle the logic for the append to the current array of data, this means it is guaranteed to always return an array. No promises broken and the components all refresh instantly after the add album is executed.
Debugging the code to print to the console showed that when I expected it should be an array, it was an album.
addAlbum: async () => {
let data = await fetchData();
let album = await addAlbum({
"id": "99",
"title": "Blue Train",
"artist": "John Coltrane",
"price": 99.99
});
data = [...data, album]
set(data);
}