svelte
svelte copied to clipboard
bind:this on a transitioned element in an #each block does not properly update the bound array
Describe the bug
When you dynamically bind elements in an #each block to an array, and those elements have a transition on them, the bound array is not kept in sync when elements are removed.
This effectively means I cannot use bind:this in an each block if elements will be removed and I want to transition them out.
Logs n/a
To Reproduce REPL
The above REPL renders an array (vals) with four items and a button to remove each item. Each <li> is dynamically bound to an element in the items array. The items array is rendered below the list to illustrate what items are being bound.
When you remove the bottom element ("orange") from the list, items is not updated. As you continue to remove elements from bottom-to-top, items stays one step behind and is out-of-sync.
items is kept in sync if you remove items top-to-bottom. Also, if you remove the transition directive from the list item, the items array seems to be kept in sync.
Example markup (see REPL for context):
{#each vals as val, i (val)}
<li
transition:scale
bind:this={items[i]}
>{val} <button on:click={() =>
remove(val, i)}>Remove</button>
</li>
{/each}
Expected behavior
The items array should be in sync with the current state of the DOM. If I remove "orange", the associated DOM element should be removed from the array (or replaced by null/undefined).
Stacktraces n/a
Information about your Svelte project:
-
Your browser and the version: Firefox 88.0
-
Your operating system: Windows 10
-
Svelte version: 3.37.0
-
Whether your project uses Webpack or Rollup: Rollup
Severity
This issue is annoying. I can work around it by calling querySelector, but that doesn't feel like the most idiomatic way to do it in Svelte.
For context, I encountered this issue when trying to render a list of inputs. I need to bind to each input so that I can call focus on them when one of them is removed. Since the bound array is not kept in-sync, sometimes the wrong input is focused.
Additional context https://github.com/sveltejs/svelte/issues/4869 seems related, but that's related to binding components instead of DOM elements.
I encountered this bug when working on https://github.com/sveltejs/kit/pull/1207.
Also, in my REPL, if you remove the first item ("apple") then the new second item ("cranberry"), there are two items left in the vals array ("banana" and "orange"), but the bound items array only contains the "orange" element in the second spot.
label: triage: bug?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This is still a bug in the latest Svelte version.
This issue has been closed as it was previously marked as stale and saw no subsequent activity.
Reopen?
Can confirm, this is still present in latest 3.58.0.
https://svelte.dev/repl/6ef0eeb08bc84f268f37281846d836e5?version=3.58.0 (as stated by the OP, remove the items from bottom to top)