svelte

Svelte perform action on a component from another component


I created a svelte modal component based on this example https://svelte.dev/examples/modal

However, since I did not want the close button coming from the modal, I removed it. The code is a below

<script lang="ts">
    export let showModal: boolean; // boolean

    let dialog: HTMLDialogElement; // HTMLDialogElement

    $: if (dialog && showModal) dialog.showModal();
</script>

<!-- svelte-ignore a11y-click-events-have-key-events a11y-no-noninteractive-element-interactions -->
<dialog
    bind:this={dialog}
    on:close={() => (showModal = false)}
    on:click|self={() => dialog.close()}
    class="backdrop:bg-slate-500/30 backdrop:dark:bg-slate-200/10"
>
    <slot />
</dialog>

I am using this Modal in another component as below

<script lang="ts">
import Modal from '$lib/components/Modal.svelte';
let showModal = false;
</script>

<button on:click={() => (showModal = true)}> OPEN MODAL </button>

<Modal bind:showModal >

  <div>cmodal content blah blah blah </div>

  <button on:click={() => (showModal = false)}> CLOSE MODAL</button>

</Modal>

Modal opens without any issues whin i click the "OPEN MODAL" button but it does not close when I click "CLOSE MODAL" button! (it closes on clicking the backdrop as expected)

What I am doing wrong? How do close the modal from within the modal?


Solution

  • The issue is quite simple but weird:

    1. The on:click only gets triggered when something inside the same file is being clicked, which your slot is technically not. This means that on:click never gets the chance to close the modal when you click the close button.
    2. Because on:click is the only function that actually calls .close() on your modal and it never gets fired, your modal can never be closed. The solution: Update the reactivity statement:
      $: {
        if (dialog) {
          if (showModal) {
            dialog.showModal();
          } else {
            dialog.close();
          }
        }
      }
    

    It is quite simple: This statement checks if the dialog is defined and then shows/closes the modal depending on the state of showModal.