0

UPDATED Here is a codesandbox recreating the issue - Modal Does not hide: https://codesandbox.io/s/vue3-popperjs-modal-64762?file=/src/components/Modal.vue

I am new to Vue and cannot figure out how to Close the modal from the Hide Modal button within the component. I am using Vue.js and Popper.js for a modal/dropdown component.

I have tried emitting, rels and passing a prop but cannot get it to function correctly. I stripped it down to the shell code below.

** Main Component **

<template>
  <div>
    <Head title="Main" />
    <div class="flex items-center">
      <div class="flex">
        <dropdown :auto-close="false" class="focus:z-10 px-4 hover:bg-gray-100 focus:border-white rounded-l focus:ring md:px-6" placement="auto">
          <template #default>
            <div class="flex">
              <button id="open" class="btn-indigo" type="button">Open Modal</button>
            </div>
          </template>
          <template #dropdown>
            <div class="mt-2 px-4 py-6 w-screen bg-white rounded shadow-xl" style="maxWidth: 600px">
              <h1>Modal Content</h1>
              <button id="close" class="btn-indigo" type="button">Hide Modal</button>
            </div>
          </template>
        </dropdown>
      </div>
    </div>
  </div>
</template>

<script>
import { Head } from '@inertiajs/inertia-vue3'
import Dropdown from '@/Shared/Dropdown'

export default {
  components: {
    Head,
    Dropdown,
  },
}
</script>

** And Dropdown Component **

 <template>
  <button type="button" @click="show = true">
    <slot />
    <teleport v-if="show" to="#dropdown">
      <div>
        <div style="position: fixed; top: 0; right: 0; left: 0; bottom: 0; z-index: 99998; background: black; opacity: 0.2" @click="show = false" />
        <div ref="dropdown" style="position: absolute; z-index: 99999" @click.stop="show = !autoClose">
          <slot name="dropdown" />
        </div>
      </div>
    </teleport>
  </button>
</template>

<script>
import { createPopper } from '@popperjs/core'

export default {
  props: {
    placement: {
      type: String,
      default: 'bottom-end',
    },
    autoClose: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      show: false,
    }
  },
  watch: {
    show(show) {
      if (show) {
        this.$nextTick(() => {
          this.popper = createPopper(this.$el, this.$refs.dropdown, {
            placement: this.placement,
            modifiers: [
              {
                name: 'preventOverflow',
                options: {
                  altBoundary: true,
                },
              },
            ],
          })
        })
      } else if (this.popper) {
        setTimeout(() => this.popper.destroy(), 100)
      }
    },
  },
  mounted() {
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Escape') {
        this.show = false
      }
    })
  },
}
</script>
Anthony Bird
  • 200
  • 2
  • 7
  • In order to help, at the minimum, we'd need to know the Vue.js and Popper versions. Ideally, you should create a *runnable* [mcve], making sure whatever bug you're seeing on local is repro-ed. (use codesanbox.io or similar). – tao Jan 22 '22 at 21:57
  • I created a Codesandbox to show what happens when I try to hide the Modal - https://codesandbox.io/s/vue3-popperjs-modal-64762?file=/src/components/Modal.vue – Anthony Bird Jan 23 '22 at 14:38
  • 1
    Changing `show=!autoclose` to `show = false` in the `@click.stop` handler of your close button will work. You don't seem to have an `autoclose` prop defined in your component, which means clicking that button will always set `show` to `true`, but you want the opposite. You also have invalid markup. You shouldn't place buttons inside other buttons. – tao Jan 23 '22 at 18:36
  • Thanks @tao - My button code was a typo in consolidating the above code to the codesandbox. Thank you for pointing out the autoclose artifact! :-) I will try removing this in the actual code. – Anthony Bird Jan 24 '22 at 22:23

0 Answers0