I'm new to Svelte and struggling with the reactive nature of passing variables to a component.
I have:
- votes = json object holding all votes for all actors
- /actors = paginated display of pages with variables passed to URL via goto (i.e. /actors?page=0&limit=10)
In actors/+page.svelte I have a loop which passes in a single actor's vote from a json object of all the actors' votes:
{#each data.actors as actor}
<Person actor={actor} vote={votes.length ? votes.filter(function (entry) {
if(entry.type === 'actor' && entry.typeId === actor.id){
return true;
}
return false;
}):{}} hasSession={!!data.session}/>
{/each}
And the component Person.svelte does some logic to calculate:
export let actor;
export let vote; //the vote json object (if exists)
let voted = vote.length ? true : false;
let lastVote = vote.length && typeof(vote[0].vote) ? vote[0].vote : false;
let voteAvg = actor.voteAvg;
let voteTotal = actor.voteTotal;
let captureVote = async function(e){
const newVote = e.target.value;
//update the card
voteAvg = voteAvg - lastVote + parseInt(newVote);
const response = await fetch('/vote', {
method: 'POST',
body: JSON.stringify({
type:'actor',
actorId: actor.id,
vote:newVote,
lastVote:lastVote,
voted:voted
}),
headers: {
'Content-Type': 'application/json'
}
});
if( !voted ){
console.log('fist vote');
voteTotal++;
voted = true;
}
}
with the variables being passed into the html as follows (Using Skeleton.dev components):
<div class="p-4 space-y-4">
<a href="/actor/{actor.id}">
<h4 class="h5 h-14 max-h-full overflow-hidden" data-toc-ignore="">{actor.name}</h4>
</a>
<div class="flex w-100 items-center space-x-4">
<div class="flex-auto flex justify-between items-center">
<span class="chip variant-filled">{voteAvg}</span>
<small class="small">{voteTotal} votes</small>
</div>
</div>
</div>
<hr class="opacity-50">
<footer class="p-2 w-100">
<RadioGroup background="none" display="flex" border="none" active="variant-filled-primary" hover="hover:variant-soft-primary">
<RadioItem bind:group={lastVote} on:click={captureVote} name="justify" value={1}><i class="fa-regular fa-thumbs-up"></i></RadioItem>
<RadioItem bind:group={lastVote} on:click={captureVote} name="justify" value={-1}><i class="fa-regular fa-thumbs-down"></i></RadioItem>
<RadioItem bind:group={lastVote} on:click={captureVote} name="justify" value={0}><i class="fa-regular fa-minus"></i></RadioItem>
</RadioGroup>
</footer>
Everything works as expected as far as paginating through actors - their details update as page/limit changes - however the "vote" object being passed in remains static to the order it was passed into on the initial load. A console.log inside Person component demonstrates that it isn't firing the calculation logic again, and/or the filtering logic is not being passed in.
I tried to change the variables in Person.svelte to be reactive - i.e.
$: voted = vote.length ? true : false;
$: lastVote = vote.length && typeof(vote[0].vote) ? vote[0].vote : false;
$: voteAvg = actor.voteAvg;
$: voteTotal = actor.voteTotal;
while this did initially appear to solve the problem (proper votes were displaying as i paginate through results), the component's logic of casting a vote and updating things like voteAvg and voteTotal no longer worked.
Not sure what I'm doing wrong but your help is greatly appreciated! :)