Reputation: 313
I have several of these which follow the same pattern.
<div class="form-control">
<label for="foo">foo</label>
<input type="text" id="foo" bind:value={foo} />
</div>
<div class="form-control">
<label for="bar">bar</label>
<input type="text" id="bar" bind:value={bar} />
</div>
I tried to create the same thing using this loop.
{#each [ foo, bar ] as v}
<div class="form-control">
<label for="{v}">{v}</label>
<input type="text" id="{v}" bind:value={v} />
</div>
{/each}
However this does not create a 2-way binding. I found that if I change either of those variables somewhere else then the changes will be reflected in the input fields. However if I type something in the input field, the variables are not updated to match. How can this be made to work? Why does the binding only work in one direction?
Upvotes: 2
Views: 1349
Reputation: 16451
To understand why it sometimes works and why it sometimes doesn't, we have to look at what actually happens.
{#each [foo, bar] as v}
In this case, when either foo or bar changes, the array has changed and the each is re-evaluated, this explains why changing the variables elsewhere triggers an update in your input field.
Now if foo and bar are simply regular variables, adding them to an array like this will add a copy of this variable and not the variable itself. This would explain why updating it inside the each loop doesn't trigger an update.
Note that if both would have been objects instead, v would hold a reference to this object instead and it would work as expected:
<script>
let A = { name: 'AA' };
let B = { name: 'BB' };
</script>
{#each [A, B] as v}
<input type="text" bind:value={v.name}>
{/each}
The above code would actually work as you expect, because of this reference.
The solution to this is to have your array start of as an actual array instead of constructing it on the fly:
<script>
let arr = ['foo', 'bar']
</script>
{#each arr as v}
<input type="text" bind:value={v}>
{/each}
Upvotes: 1
Reputation: 11706
Something like this will reflect input changes:
<script>
let obj = { foo: 1, bar: 2 }
</script>
<p>{Object.values(obj).join(', ')}</p>
{#each Object.keys(obj) as k}
<div class="form-control">
<label for="{k}">{k}</label>
<input type="text" id="{k}" bind:value={obj[k]} />
</div>
{/each}
Upvotes: 3