Giter VIP home page Giter VIP logo

Comments (2)

danperks avatar danperks commented on June 5, 2024 1

Hi, thanks for the in-depth response. I investigated this further since posting the issue and eventually settled on handling which item was clicked myself.

On the context menu event, I'd pass the item that was right clicked to the event handler, where I stored it in a ref. Then, on the events that require the specific right clicked element, I just refer to that variable. Bit of a cheat, but very simple to understand at least 🤷‍♂️

Here's an updated PoC with that implemented: https://stackblitz.com/edit/nuxt-ui-6oeqq4

Thanks for you're suggestion regardless, your method would probably have been my next attempt!

from ui.

antalasztrik avatar antalasztrik commented on June 5, 2024

I think the problem might be the fact that you are binding the :virtual-element prop to the same ref in every iteration. This way the virtualElement's value is actually the one you set in the last iteration of the v-for, so it doesn't matter which ContextMenu you click, it will be the one set in the last iteration, thus having the last item passed into the logClicked function all the time.

I think what you might probably want to do is create different virtualElement objects for your UContextMenu components.

Not sure if this is what you wanted to achieve, but one solution could be to use an array to handle the different UContextMenus v-model and virtualElement attributes:

<template>
  <UContainer class="min-h-screen flex items-center">
    <UCard
      @click="logClicked(item)"
      v-for="(item, i) in items" // get the index, so you can bind the components
      @contextmenu.prevent="() => onContextMenu(i)" // you can use the index to signal which ContextMenu triggered the event
      :key="item"
      class="flex-1"
      :ui="{
        background: 'bg-gray-50 dark:bg-gray-800/50',
        ring: 'ring-1 ring-gray-300 dark:ring-gray-700',
        divide: 'divide-y divide-gray-300 dark:divide-gray-700',
        header: { base: 'font-bold' },
      }"
    >
      <p>{{ item }}</p>
      <UContextMenu v-model="isOpen[i]" :virtual-element="virtualElements[i]"> // bind it to the correct objects
        <p class="hover:bg-gray-100 p-4" @click="logClicked(item)">Copy Link</p>
      </UContextMenu>
    </UCard>
  </UContainer>
  <UNotifications />
</template>

<script setup>
// Context Menu Setup

const { x, y } = useMouse();
const { y: windowY } = useWindowScroll();

const isOpen = ref([false, false, false]); // use an array to handle different ContextMenu open states
const virtualElements = ref([ // the same, just with the virtualElement attributes
  { getBoundingClientRect: () => ({}) },
  { getBoundingClientRect: () => ({}) },
  { getBoundingClientRect: () => ({}) },
]);

function onContextMenu(index) {
  const top = unref(y) - unref(windowY);
  const left = unref(x);

  // set the correct ContextMenu virtualElement data
  virtualElements.value[index].getBoundingClientRect = () => ({ 
    width: 0,
    height: 0,
    top,
    left,
  });

  isOpen.value[index] = true; // set the correct ContextMenus open state
}

// PoC Setup
const items = ['Item 1', 'Item 2', 'Item 3'];

const logClicked = (item) => {
  console.log('The item that was clicked is: ' + item);
  alert('The clicked item is: ' + item);
};
</script>

<style>
body {
  @apply antialiased font-sans text-gray-700 dark:text-gray-200 bg-white dark:bg-gray-900;
}
</style>

There might be other solutions, like refactoring out this component to its own component, having it own its state. For example, you could create a CopyLinkCard component, that has it's own isOpen and virtualElement state and onContextMenu function - that way you can be sure, that they are not going to interfere in a v-for, meaning you can leave out the whole array and index stuff I just wrote before.

I hope this is what you were looking for and also hope my answer made sense.

from ui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.