Search code examples
sveltesvelte-3

targeting a specific element in iteration using js and svelte


I love and use svelte in everything but this a new issue that I've never encountered before and I'm unable to figure a solution.

I'm using svelte to iterate over an array :

<section>
    <h5>Players</h5>
    {#each players as aplayer}
    <li>
        {aplayer.name} - {aplayer.rank}
        <button on:click={()=>update_rank(aplayer)} >update rank</button>       
      
    </li>
    {/each}
  </section>

Once the rank is updated, I want to disable that button. After I disable it, I need to add another button just available to this play and not to all the buttons in the each block. How do you add an element or remove an element specific to an element in the each block? How to target an element in each block? There must be a way I can find the id for that element?


Solution

  • Do not mess with the DOM/IDs etc. Svelte is not intended to be used that way and it will only cause issues, besides being more complicated than the alternative.

    You can just use the data to drive the DOM. So if the button should be disabled depending on rank, you can just set that in the markup. To show/hide things you can use {#if}.

    Though, if logic is extracted to a function and the passed object is mutated inside that, this breaks the reactive association with the source. There are various options, like returning a relevant value and assigning it in the markup; the easiest thing to do is adding a dummy assignment for the source list, though this can have a performance impact for very large lists.

    <script>
        let players = [
            { name: 'Player A', rank: null },
            { name: 'Player B', rank: null },
        ];
    
        function updateRank(player) {
            player.rank = 1;
            players = players; // <- forces update
        }
    </script>
    
    {#each players as player}
        <div>
            {player.name} - {player.rank}
            <!-- Just add a disable condition here: -->
            <button disabled={player.rank != null}
                on:click={() => updateRank(player)}>
                Update Rank
            </button>
            <!-- Show condition here: -->
            {#if player.rank != null}
                <button>Something else</button>
            {/if}
        </div>
    {/each}
    

    REPL