I have a list of players from which I can remove a player by clicking a button, to make it more dynamic I added a fly transition when the element is removed, here’s the code:
<script lang="ts">
import { fly } from 'svelte/transition';
let players: string[] = ['Juan', 'John', 'Luis'];
</script>
<div class="overflow-hidden">
{#each players as player, playerIndex}
{#key playerIndex}
<div class="flex" out:fly={{ duration: 2000, x: '100vw', opacity: 100 }}>
<span>{player}</span>
<button
on:click={() => {
players.splice(playerIndex, 1);
players = players;
}}
>
Remove
</button>
</div>
{/key}
{/each}
</div>
The problem with this is that it removes the right element but the transition is always applied to the last element, so it looks like the last element is being removed.
I want it to look like the deleted element flies out the screen leaving an empty space, and then the list is adjusted to fill the empty space. So I tried a different aproach, I created a store for the players and created a Player component, here’s the code:
lib/playersStore.js
import { writable } from 'svelte/store';
export const players = writable(['Juan', 'John', 'Luis']);
+page.svelte
<script lang="ts">
import { players } from '$lib/playersStore';
import Player from './Player.svelte';
</script>
<div class="overflow-hidden">
{#each $players as player, playerIndex}
<Player {player} {playerIndex} />
{/each}
</div>
Player.svelte
<script lang="ts">
import { players } from '$lib/playersStore';
import { fly } from 'svelte/transition';
export let player: string;
export let playerIndex: number;
let didRemoveElement = false;
const transitionDuration = 2000;
function removePlayer() {
didRemoveElement = true;
setTimeout(() => {
$players.splice(playerIndex, 1);
$players = $players;
}, transitionDuration);
}
</script>
{#if !didRemoveElement}
<div class="flex" out:fly={{ duration: transitionDuration, x: '100vw', opacity: 100 }}>
<span>{player}</span>
<button on:click={removePlayer}> Remove </button>
</div>
{/if}
This way it waits for the transition to finish and then it rerenders the list of players, but now the problem is that it removes the last element from the DOM, if I log the list of players to the console it still shows the last element but for some reason it’s not on the view anymore.
That’s all I’ve tried with no success, thanks to anyone who can help me out.
>Solution :
You should key your each.
{#each $players as player, playerIndex (player.id)}
Try to find a good key for your each block. Ideally, you have an ID property.