user3541631
user3541631

Reputation: 4008

Open/Close a modal using Vue3 composition API doesn't work as expected

I want to build a simple open/close Modal, using Vue3 composition API, but it doesn't work.

If I use v-if (as in the code below) the modal doesn't open, if I use v-show the modal opens but the close button doesn't work.

As an addition, add a eventListener for ESC key, and then remove it on unMounted.

App.vue

    <div class="min-h-screen flex items-center justify-center">
          <button @click="isModalOpen = true" type="button" class="btn btn-blue">Open Modal</button>
        </div>
    
        <announcement-modal
            v-if="isModalOpen"
            @click="isModalOpen = true"
            v-model:isOpen="isModalOpen">
    
        </announcement-modal>
      </div>
    </template>
    
    <script>
    
    import { ref } from "vue";
    import AnnouncementModal from "./components/AnnouncementModal";
    
    export default {
      components: {
        AnnouncementModal,
      },
      setup() {
        const isModalOpen = ref(false);
    
        return {
          isModalOpen,
        }
      },
    
    }
    </script>

Announcement.vue

        <div class="text-center">
            <button @click="closeModal" type="button" class="btn btn-blue">
              Dismiss
            </button>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    
    import { onUnmounted } from "vue"
    export default {
      props: ["isOpen"],
      setup(props, context) {
    
        onUnmounted(function () {
          console.log("after unmounted")
        });
    
        function closeModal() {
          context.emit("update:is-open", false);
        }
    
        return {
          closeModal
        }
      }
    }

Upvotes: 0

Views: 6579

Answers (1)

Dan Knights
Dan Knights

Reputation: 8368

The @click="isModalOpen = true" is immediately opening it every time you click to close the modal.

Remove this event handler and it should work:

const app = Vue.createApp({
  setup() {
    const isModalOpen = Vue.ref(false);

    return {
      isModalOpen
    }
  },
});

app.component('announcement-modal', {
  template: `<div class="text-center">
            <button @click="closeModal" type="button" class="btn btn-blue">
              Dismiss
            </button>
      </div>`,
  setup(props, context) {
    Vue.onUnmounted(function() {
      console.log("after unmounted")
    });

    function closeModal() {
      context.emit("update:is-open", false);
    }

    return {
      closeModal
    }
  }
})

app.mount('#app')
<script src="https://unpkg.com/vue@next"></script>

<div id="app">
  <div class="min-h-screen flex items-center justify-center">
    <button @click="isModalOpen = true" type="button" class="btn btn-blue">Open Modal</button>
  </div>

  <announcement-modal v-if="isModalOpen" v-model:is-open="isModalOpen"></announcement-modal>
</div>

Also, as @Dan said, the v-model:isOpen="isModalOpen" shouldn't be camelCase.

Upvotes: 2

Related Questions