I have an array in svelte. I add elements to the front of an array. If the user opens a modal attached to a component generated by the array, when a new item is added, the modal changes based on the index.
E.g. a list of [3,2,1]
would make 3 buttons that when clicked open a modal. If the modal were opened and then the list were updated to be [4,3,2,1]
, the modal be updated to whichever element replaced its position. My desire is to not have the modal update while maintaining the way the array is updated.
TL;DR adding elements to an array destroys the state of a child modal
Each block:
{#each items as item}
<MakeItem item={item}></MakeItem>
{/each}
I've tried using and not using bind:item
and it makes no difference.
MakeItem
<script>
import Modal from './Modal.svelte';
export let item
let showModal = false;
</script>
<button on:click={() => (showModal = true)}>
show modal {item}
</button>
<Modal bind:showModal>
item: {item}
</Modal>
Modal
<script>
export let showModal; // boolean
let dialog; // HTMLDialogElement
$: if (dialog && showModal) dialog.showModal();
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<dialog
bind:this={dialog}
on:close={() => (showModal = false)}
on:click|self={() => dialog.close()}
>
<div on:click|stopPropagation>
<slot name="header" />
<hr />
<slot />
<hr />
<!-- svelte-ignore a11y-autofocus -->
<button autofocus on:click={() => dialog.close()}>close modal</button>
</div>
</dialog>
<style>
dialog {
max-width: 32em;
border-radius: 0.2em;
border: none;
padding: 0;
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.3);
}
dialog > div {
padding: 1em;
}
dialog[open] {
animation: zoom 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes zoom {
from {
transform: scale(0.95);
}
to {
transform: scale(1);
}
}
dialog[open]::backdrop {
animation: fade 0.2s ease-out;
}
@keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
button {
display: block;
}
</style>