Vue.js custom confirmation component failing to open within v-menu

I am having trouble displaying a confirmation component every time a button in the header is clicked. Currently, it only opens when clicking elements outside of the dropdown using v-menu.

App.vue

<template>
  {{isConfirmDialogVisible}}
  <div class="header">
    <div class="left-menus">
      <div
        v-for="(item, index) in items"
        :key="index"
        class="menu"
        style="background-color: red; gap: 10px; padding: 10px"
        @click="opendialog()"
      >
        {{ item.title }}
      </div>
    </div>
    <v-menu open-on-hover transition="slide-y-transition">
      <template #activator="{ props }">
        <div style="cursor: pointer">
          <v-icon v-bind="props">mdi-menu-down</v-icon>
        </div>
      </template>

      <v-list>
        <v-list-item
          v-for="(item, index) in userOptions"
          :key="index"
          class="dropdown"
          @click="opendialog()"
        >
          <v-list-item-title>{{ item.title }}</v-list-item-title>
        </v-list-item>
      </v-list>
    </v-menu>
    <Confirmation
      v-model="isConfirmDialogVisible"
      v-if="isConfirmDialogVisible"
      action-button="submit"
      action-button-left="cancle"
      action-button-right="confirm"
    >
      <div style="font-size: 20px">Are you sure?</div>
    </Confirmation>
  </div>
</template>

<script>
  import { ref } from 'vue'
  import Confirmation from './Confirmation.vue'

  const isConfirmDialogVisible = ref(false)

  const userOptions = ref([{ title: 'Logout' }, { title: 'Setting' }])

  const opendialog = () => {
    isConfirmDialogVisible.value = true
  }

  export default {
    components: {
      Confirmation,
    },
    data: () => ({
      items: [
        { title: 'Click Me' },
        { title: 'Click Me' },
        { title: 'Click Me' },
        { title: 'Click Me 2' },
      ],

      opendialog,
      isConfirmDialogVisible,
      userOptions,
    }),
  }
</script>

<style>
  .header .left-menus {
    display: flex;
    align-items: center;
    gap: 16px;
  }
</style>

Confirmation.vue

<template>
  <v-dialog v-model="dialogVisible" persistent activator="parent" width="auto">
    <div class="dialog_container">
      <v-card>
        <div class="card-components">
          <div class="warning_image"></div>
          <v-card-text>
            <slot></slot>
          </v-card-text>
          <v-card-actions>
            <v-btn class="back" @click="closeDialog"
              >{{ actionButtonLeft }}</v-btn
            >
            <v-btn @click="confirmSelection" class="confirm-submit">
              {{ actionButtonRight}}
            </v-btn>
          </v-card-actions>
        </div>
      </v-card>
    </div>
  </v-dialog>
</template>
<script>
  import { ref } from 'vue'

  export default {
    props: {
      modelValue: Boolean,
      actionButton: {
        type: String,
        required: true,
      },
      actionButtonRight: {
        type: String,
        required: true,
      },
      actionButtonLeft: {
        type: String,
        required: false,
        default: 'cancel',
      },
    },

    emits: ['update:modelValue', 'confirmAction'],
    setup(props, { emit }) {
      const dialogVisible = ref(false)
      const closeDialog = () => {
        dialogVisible.value = false
        emit('update:modelValue', false)
      }
      const confirmSelection = () => {
        closeDialog()
        emit('confirmAction')
      }

      const returnBack = () => {
        closeDialog()
      }

      const handleOutsideClick = event => {
        console.log(event)
      }

      return {
        dialogVisible,
        closeDialog,
        returnBack,
        confirmSelection,
        handleOutsideClick,
      }
    },
  }
</script>

<style scoped>
  .card-components {
    display: flex;
    flex-direction: column;
    gap: 24px;
  }

  .dialog_container {
    height: 225px;
    width: 648px;
  }
  .v-card {
    padding: 16px 24px 24px 24px;
  }
  .v-card-text {
    padding: 0;
  }
  .warning_image {
    display: flex;
    width: 100%;
    justify-content: center;
  }

  .v-card-actions {
    min-height: 0;
    padding: 0;
    display: flex;
    justify-content: flex-end;
  }
  .v-card-actions .v-btn {
    border: 1px solid #9ca3af;
    color: #9ca3af;
    width: 140px;
    justify-content: center;
    align-items: center;
    border-radius: 4px;
  }

  .v-card-actions .confirm-submit {
    color: white;
    border: 1px solid #41a1e0;
    background: #41a1e0;
  }
</style>

I am facing issues with showing a confirmation component whenever a button is clicked in the header. It seems to be opening only when elements other than the dropdown are clicked using v-menu.

Answer №1

Within the Confirmation.vue file, the VDialog component depends on the parent component to be displayed:

<template>
  <v-dialog v-model="dialogVisible" activator="parent">
  ...
</template>
<script setup>
  const dialogVisible = ref(false)
  ...
</script>

Hence, when a Confirmation component is visible, the VDialog will render the dialog and update the dialogVisible state.

However, this mechanism fails when VMenu is visible. Instead, it's recommended to utilize the component's modelValue to trigger the dialog, which is more meaningful. There are multiple ways to achieve this, one of them being setting dialogVisible within a watcher:

setup(props, { emit }) {
  const dialogVisible = ref(false)
  watchEffect(() => dialogVisible.value = props.modelValue)

In order for this setup to function correctly, the activator="parent" attribute needs to be removed.

You can test this implementation in a playground

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a Vue application without the use of vue-cli and instead running it on an express

Vue has an interesting feature where vue-cli is not necessary for running it without a server. Initially, I thought otherwise. The Vue installation page at https://v2.vuejs.org/v2/guide/installation.html mentions using a script under CDN. <script src=&q ...

Exploring the capabilities of Node.js functions

I'm currently exploring Node.js and struggling to understand how functions are created and used. In my code snippet: var abc={ printFirstName:function(){ console.log("My name is abc"); console.log(this===abc); //Returns true ...

What is the best method for conducting comprehensive testing of all projects and libraries within NestJS (nx)?

Our NestJS project has been established with multiple libraries through Nx. We have successfully run tests on individual projects/libraries using the following command: npx nx test lib1 --coverage While this method works well, we are faced with numerous l ...

Resolving a CSS Layout Dilemma: How to Overlay Sidebar on Wrappers

I've run into a challenge while attempting to position a sidebar over page wrappers. The issue with absolute positioning arises when the sidebar needs to align with the corner of the blue header. I have contemplated using JavaScript to maintain its cu ...

Encountered an issue with instafeed.js due to CORS policy restrictions

Trying to implement an API that provides JSON data for use in a function. Required Imports: Importing Jquery, instafeed.min.js, and the API (instant-tokens.com). <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js& ...

Using TypeScript arrow function parentheses in the filter function

If I have an array of movie objects like this: const movies: Movie[] = [ movie1, movie2, movie3, movie4 ]; And if I want to remove a specific movie from the array, such as movie2, I can use the following code: movies = movies.filter( m => m !== ...

JavaScript problem with setting values in 2D array

I am attempting to assign values to a 2d array at particular indices. During each iteration, all sub-arrays at the j index are being assigned the same variable (number). inputTensor dimensions: 140x7 - 140 arrays of size 7 inputMinArray dimensions: 1x7 - ...

Ways to grant entry to a Vue.js page exclusively to authenticated users or when localStorage is present

My Vue.js application is set up with vue-router as shown below. index.html <p> <router-link to="/" exact> Home </router-link> <router-link to="/about"> About </router-link> <router-link to="/contact"> Contact < ...

Troubleshooting CORS, OPTIONS, and PreFlight issues when using Axios to consume a REST API in a Vue.js project

Currently, I am working on developing the front end for a PHP-based application that utilizes a custom management tool. My approach involves using Vue.js to construct the front end and specifically employing Axios to make API calls. I have set up a Lights ...

Utilize Node.js to proxy Angular requests to a service hosted on Azurewebsites

I am trying to set up a proxy post request in my Node.js server and receive a response from the target of this request. Below is an excerpt from my server.js file code where I have implemented the proxy, but I am facing a issue with not receiving any respo ...

Shut down the active tab

For some reason, using window.close(); in my JavaScript script is not closing the currently opened tab as expected. I'm looking for a way to automatically close a manually opened tab using a JavaScript function. Any ideas on what might be going wrong? ...

Working on asynchronous processing of Highland stream fragments

My current setup involves utilizing highland.js to process a file using a stream and extract content between specific delimiters. Additionally, I am incorporating async.js to perform a sequence of http requests. I am seeking a way to pass the output x fro ...

Conditional rendering of a component in ReactJS while maintaining the "empty" space

Is there a way to conditionally render a component without affecting the layout of other components? I'm trying to avoid unwanted shifts caused by this div Do you have any suggestions? Here is a snippet of my code: const [displayFeedbackMessage, s ...

Develop a React component that organizes an array based on specified index ranges in JavaScript

Imagine having an array structured like this: let numbers = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17, 18, 19]; I am interested in creating a React component that displays the elements of the array in groups of 10. The desired output should look like t ...

Struggling to synchronize animation timing between elements using jquery

When you navigate to an album (for example, Nature because I'm still working on the others) and select one of the images, they all gradually fade out while the selected image appears on the screen. What's actually happening is that the selected i ...

I'm encountering a RangeError in nextjs when trying to pass props to a child component

I'm a beginner with Next.js. I've been attempting to pass props to a child component that is a response from an API call. However, every time I try to add the props in the child component, I encounter a RangeError: Maximum call stack size exceed ...

Rendering the HTML5 canvas within a console environment

I am looking to create images of humans on the console using nodejs. In order to achieve images of higher quality, I require a library or module that can facilitate drawing images in the console. Some options available include imaging and console-png. How ...

How to dynamically disable options in a Vuetify v-select based on the type of object value

When utilizing the Vuetify v-select component and setting the prop multiple, we can select multiple values at once. In this scenario, I have a variety of recipes categorized under Breakfast or Dinner using the parameter type. The goal is to deactivate al ...

Using JSON in JavaScript to handle the click event of ASP.NET buttons

Here is the code that works well for me. I need to execute two different server-side functions, and they can't run at the same time as I have separated them. Default.aspx/AddCart btnUpdate Click Event The issue I'm facing is that the alert box ...

What steps should I take to make this slider functional?

How can I achieve a sliding effect on this code? I want the div to slide out when the button is clicked, but I also want the button itself to move. Additionally, how can I ensure that the image and text are displayed in two columns? In my IDE, it appears a ...