Jan Tvrdík
Jan Tvrdík

Reputation: 395

How to bind variable declared with Svelte let directive?

I'm trying to workaround "Cannot bind to a variable declared with the let: directive" error.

// FancyList.svelte
<script>
    export let items = []   
</script>

<ul>
    {#each items as item, i}
        <li><slot item={item}></slot></li>
    {/each} 
</ul>

// App.svelte
<script>
    import FancyList from './FancyList.svelte'
    let items = [ {x: 'AX', y: 'AY'}, {x: 'BX', y: 'BY'}, {x: 'CX', y: 'CY'}]
</script>

<FancyList bind:items={items} let:item={item}>
    <input type=text bind:value={item.x}>
    <input type=text bind:value={item.y}>
</FancyList>

Available as Svelte REPL

Things I have tried so far

1) Making FancyList to pass item index instead of item itself and binding items[index] instead of item.

<FancyList items={items} let:index={index}>
    <input type=text bind:value={items[index].x}>
    <input type=text bind:value={items[index].y}>
</FancyList>

Available as Svelte REPL

This will initially render properly but will emit "ReferenceError: index is not defined" error upon input value change.

2) Making FancyList to pass onChange callback and not using bind.

<FancyList bind:items={items} let:item={item} let:onChange={onChange}>
    <input type=text value={item.x} on:input={e => onChange({...item, x: e.target.value})}>
    <input type=text value={item.y} on:input={e => onChange({...item, y: e.target.value})}>
</FancyList>

Available as Svelte REPL.

This works but is significantly more verbose.

Upvotes: 18

Views: 10805

Answers (2)

suddjian
suddjian

Reputation: 2396

You can use svelte:component to accomplish this. It basically will let you pass a component to your FancyList, making it a Higher Order Component of sorts.

Here's a REPL example that shows it working:

https://svelte.dev/repl/bc985c21735f4b2a9945f1ddc74988e6?version=3.6.1

Upvotes: 2

Rich Harris
Rich Harris

Reputation: 29585

It's a bug that your first solution attempt didn't work — I've raised an issue. Another possible workaround is to put the update logic in the parent component, so that the child component doesn't need to have any special awareness of the parent's requirements: https://svelte.dev/repl/2d13c33c34f445d99618fbb1bc8bebb9?version=3.6.1. It's about the same as your second solution, verbosity-wise.

Upvotes: 12

Related Questions