Search code examples
svelte-3

How to show header for grouped names in Svelte?


I'm currently using Svelte to show a list of names and I want to show a headline every time the name in the list changes, so the user has a clear view of the grouped names.

In this example I'm using the names ['Amber','Amber', 'Brian', 'Charlie','Charlie'].

My expected output would be

<strong>Amber</strong><br>
Amber<br>
Amber<br>
<strong>Brian</strong><br>
Brian<br>
<strong>Charlie</strong><br>
Charlie<br>
Charlie<br>

I've put together a small snippet to show my problem;

<script>
let names = ['Amber','Amber', 'Brian', 'Charlie','Charlie'];
let currentName = '';

function setCurrentName(newName) {
    currentName = newName;
    return '';
}
</script>

{#each names as name}
<div>
    {#if (name != currentName)}
        <strong>{name}</strong><br>
        {setCurrentName(name)}
    {/if}
    {name}
</div>
{/each}

Link to Svelte Repl

but the outputted list looks like this;

<strong>Amber</strong>
Amber
<strong>Amber</strong>
Amber
<strong>Brian</strong>
Brian
Charlie
Charlie

As you can see, we have 2 strong Ambers, one strong Brian and no strong Charlie.

  • I'm using a callback function inside the loop, as suggested by this answer.

  • I have also tried to simply assign currentName to name by doing a {currentName = name}

My question now is;

Why does Svelte behave like this and what can I do to fix it?


Solution

  • One way to fix this is to access the index in the each block (which allows directly accessing the previous element of the array) instead of updating the component's state inside the loop.

    {#each names as name, i}
    <div>
        {#if (name != names[i - 1])}
            <strong>{name}</strong><br/>
        {/if}
        {name}<br/>
    </div>
    {/each}