floating-vue icon indicating copy to clipboard operation
floating-vue copied to clipboard

Close nested VDropdown without closing parent programmatically

Open kduvignau opened this issue 3 years ago • 12 comments

Hello! I would like to close a nested VDropdown inside another VDropdown.

I tried with the v-close-popper directive on the div node and it works. However, I would like to do some processing (async calls for example) before closing the popper so I can't use the directive as-is.

I also tried to use the hide method exposed by the #popper slot, I got the same result.

I also don't want to use :auto-hide="false" on the parent VDropdown because I want to autoclose when the click is outside

Here is a minimal example, when I click on Hello, the nested AND the parent VDropdown close.

<template>
  <div class="example flex justify-center items-center gap-6">
    <VDropdown placement="bottom-start">
      <button class="border border-gray-300 rounded px-4 py-2">Click me</button>

      <template #popper>
        <VDropdown v-model:shown="open" placement="right-start">
          <button class="rounded hover:bg-green-100 px-4 py-2">Option ></button>

          <template #popper>
            <div class="px-6 py-2" @click="onClick">Hello</div>
          </template>
        </VDropdown>
      </template>
    </VDropdown>
  </div>
</template>

<script setup>
import { ref } from "vue";
const open = ref(false);

function onClick() {
  // Some processing ...
  open.value = false;
}
</script>

kduvignau avatar Jul 01 '22 19:07 kduvignau

bump

Reproduction: https://stackblitz.com/edit/vitejs-vite-t58z89?file=src%2FApp.vue

Expected behavior: only the closest dropdown is closed when calling the hide method Current behavior: the all dropdown hierarchy closes

or2e avatar Jun 02 '23 09:06 or2e

Same here, really need to fix it!

zhaivoronok avatar Jun 20 '23 11:06 zhaivoronok

zhaivoronok, kduvignau Very dirty hack, nothing seems to be broken (but it's not for sure)

https://github.com/Akryum/floating-vue/blob/main/packages/floating-vue/src/components/Popper.ts#L454

if (this.shownChildren.size > 0) {
-   this.$_pendingHide = true
    return
}

https://github.com/Akryum/floating-vue/blob/main/packages/floating-vue/src/components/Popper.ts#L477

- this.$_scheduleHide(event, skipDelay)
+ setTimeout(() => {
+  this.$_scheduleHide(event, skipDelay)
+ }, 0);

or2e avatar Sep 16 '23 23:09 or2e

Thanks for providing your solution @or2e !

FYI, there is an official package for floating ui for Vue, you can find out here : https://www.npmjs.com/package/@floating-ui/vue

kduvignau avatar Sep 17 '23 01:09 kduvignau

Hi was this fixed? @zhaivoronok @kduvignau @or2e

ishaiavrahami avatar Dec 06 '23 18:12 ishaiavrahami

Solution:

<template>
  <Dropdown :shown="open" @show="onShow" @hide="onHide">
    <slot></slot>
    <div slot="popper"></div>
  </Dropdown>
</template>

<script>
import { Dropdown } from 'v-tooltip'

export default {
  name: 'Popover',
  components: {
    Dropdown,
  },
  data() {
    return {
      autoHide_: this.autoHide,
      isOpened: false,
    }
  },
  watch: {
    autoHide(newValue) {
      this.autoHide_ = newValue
    },
  },
  methods: {
    setParentAutoHideToFalse() {
      let parent = this.$parent
      while (parent) {
        if (parent.$el.classList.contains('v-popper') && parent.isOpened) {
          parent.autoHide_ = false
          if (parent.$el.parentNode === document.body) {
            break
          }
        }
        parent = parent.$parent
      }
    },
    setParentAutoHideToTrue() {
      let parent = this.$parent
      while (parent) {
        if (parent.$el.classList.contains('v-popper') && parent.isOpened) {
          parent.autoHide_ = true
          break
        }
        parent = parent.$parent
      }
    },
    onShow() {
      this.isOpened = true
      setTimeout(() => this.setParentAutoHideToFalse(), 200)
    },
    onHide() {
      this.isOpened = false
      setTimeout(() => this.setParentAutoHideToTrue(), 100)
    },
  },
}
</script>

RAIbrahim360 avatar Dec 15 '23 16:12 RAIbrahim360

@ishaiavrahami No ( Updated the reproduction: https://stackblitz.com/edit/vitejs-vite-kfcze6?file=src%2FApp.vue

or2e avatar Jan 30 '24 14:01 or2e

This is still not resolved after two years?

vkolova avatar Feb 16 '24 08:02 vkolova