Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Svelte, apply transition to element when being removed from array

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading