Search code examples
javascriptsveltesvelte-3

Svelte application bug: converting string to boolean in the view fails


In a Svelte app, I have this array of countries:

let countries = [
    {
        name:"Alegeria",
        status: "1"
    },
    {
        name:"Bulgaria",
        status :"0"
    }
]

Note the status property is a string. I iterate the array this way:

{#if countries.length > 0}
<table class="table">
    <thead>
        <tr>
            <th>Country</th>
            <th class="text-right">Status</th>
        </tr>
    </thead>
    <tbody>
        {#each countries as c}  
        <tr>
            <td>{c.name}</td>
            <td class="text-right"><Switch bind:checked={Boolean(Number(c.status))} /></td>
        </tr>
    {/each}
    </tbody>
</table>
{:else}
<p class="alert alert-danger">No countries found</p>
{/if}

As you can see, I try to convert the value of the status property to a boolean this by using Boolean(Number(c.status)).

Instead of the desired conversion I get the error: Can only bind to an identifier (e.g. foo) or a member expression as the REPL shows.

What am I doing wrong?


Solution

  • As it says in the error, you can only bind to an identifier or member expression - ie a variable.

    This is because a bind is a two-way thing, and if you have applied Boolean(Number(()) to it, when someone changes that input, then svelte doesn't know how to undo those functions to 'save' the data back into that variable it's bound to.

    If you can't change the status variables to be boolean (better solution, as suggested by other answers), you need to manually do this two-way updating. Drop the bind, just have checked={Boolean(Number(c.status))}, and handle the input's change event to convert from true/false back into "1" or "0", and save that to the status.

    Use:

    function handleClick(country) {
        countries.find(c => c.name == country.name).status = (country.status == "1") ? "0" :"1"
    }
    

    and

    <Switch checked={Boolean(Number(c.status))} on:change={() => handleClick(c)}/>
    

    See it working in this repl