svelte icon indicating copy to clipboard operation
svelte copied to clipboard

bind:this on a transitioned element in an #each block does not properly update the bound array

Open geoffrich opened this issue 3 years ago • 6 comments

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.

geoffrich avatar Apr 27 '21 18:04 geoffrich

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.

geoffrich avatar Apr 27 '21 18:04 geoffrich

label: triage: bug?

Zachiah avatar Jun 05 '21 17:06 Zachiah

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.

stale[bot] avatar Dec 02 '21 18:12 stale[bot]

This is still a bug in the latest Svelte version.

geoffrich avatar Dec 02 '21 18:12 geoffrich

This issue has been closed as it was previously marked as stale and saw no subsequent activity.

stale[bot] avatar Dec 16 '21 19:12 stale[bot]

Reopen?

homerjam avatar Jul 13 '22 18:07 homerjam

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)

ptrxyz avatar Apr 17 '23 18:04 ptrxyz