0

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

REPL link

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>

pilchard
  • 12,414
  • 5
  • 11
  • 23
Brandon Kauffman
  • 1,515
  • 1
  • 7
  • 33

0 Answers0