hiding a dropdown menu in vuejs when clicking outside of it

Utilizing dropdown menu components in vuejs to create a standard dropdown menu. The code for the dropdown component is as follows:

<template>
    <span class="dropdown" :class="{shown: state}">
        <a href="#" @click.prevent="toggleDropdown" class="dropdown-toggle">toggle menu</a>
            <div class="dropdown-menu" v-show="state">
                <ul class="list-unstyled">
                    <slot></slot>
                </ul>
            </div>
        </transition>
    </span>
</template>

<script>
export default {
    name: 'dropdown',
    data () {
        return {
            state: false
        }
    },
    methods: {
        toggleDropdown (e) {
            this.state = !this.state;
        }
    }
}
</script>

Now I am including the dropdown component in my VUE app at different places using the following code in the template

<dropdown>
    <li>
         Action
    </li>
</dropdown>

Everything seems to be working fine, but I desire to have only one dropdown active at any given time.

After some research, I discovered that there are plugins like https://github.com/davidnotplay/vue-my-dropdown, however, I prefer not to use them. I have also investigated how the earlier example functions, but I aim to implement this dropdown feature so that my dropdown component can handle all event interactions related to the dropdown. Can you assist me with achieving this?

Answer №1

Although this question is from a while back, I believe the most effective way to achieve this without relying on external plugins is by incorporating a click listener in the mounted lifecycle hook (and removing it in the beforeDestroy hook) to filter out clicks on your component and ensure it only hides when clicked outside.

<template>
    <span class="dropdown" :class="{shown: state}">
      <a href="#" @click.prevent="toggleDropdown" class="dropdown-toggle">toggle menu</a>
            <div class="dropdown-menu" v-show="state">
                <ul class="list-unstyled">
                    <slot></slot>
                </ul>
            </div>
        <transition/>
    </span>
</template>

<script>
export default {
  name: 'dropdown',
  data () {
    return {
      state: false
    }
  },
  methods: {
    toggleDropdown (e) {
      this.state = !this.state
    },
    close (e) {
      if (!this.$el.contains(e.target)) {
        this.state = false
      }
    }
  },
  mounted () {
    document.addEventListener('click', this.close)
  },
  beforeDestroy () {
    document.removeEventListener('click',this.close)
  }
}
</script>

Answer №2

Implementing the functionality in Vue 3

Take note that using @click.stop on both the dropdown trigger and content blocks prevents the document event from triggering the close function.

<template>
  <div class="dropdown" :class="{'is-active': dropdown.active.value}">
    <div class="dropdown-trigger">
      <button class="button" @click.stop="dropdown.active.value = !dropdown.active.value">
        Toggle
      </button>
    </div>
    <div class="dropdown-menu" role="filter">
      <div class="dropdown-content" @click.stop>
        <!-- dropdown items -->
      </div>
    </div>
  </div>
</template>

<script>

import { defineComponent, ref, onMounted, onBeforeUnmount } from "vue";

export default defineComponent({
  name: "Dropdown",
  setup(){
    const dropdown = {
      active: ref(false),
      close: () => {
        dropdown.active.value = false
      }
    }

    onBeforeUnmount(() => {
      document.removeEventListener('click', dropdown.close)
    })

    onMounted(() => {
      document.addEventListener('click', dropdown.close)
    })

    return {
      dropdown
    }
  }
})

</script>

This demonstration utilizes the bulma framework, but it is adaptable to any other framework as well.

Answer №3

Check out a helpful tool called vue-clickaway. You can find more information about it here.

At times, it's necessary to detect clicks outside of an element (for example, to close a modal window or hide a dropdown select). No native event exists for this purpose, and Vue.js doesn't provide a solution either. This is where the vue-clickaway plugin comes in handy. Make sure to view the demo first before delving deeper.

Answer №4

If you want to hide a dropdown whenever a toggle link loses focus, you can utilize the `blur` event along with a method like this:

hideDropdown() {
    setTimeout(() => {
        this.isVisible = false;
    }, 200);
}

Simply add the `blur` event to your link element:

<a href="#" @click.prevent="toggleDropdown" @blur="hideDropdown">Toggle Menu</a>

This way, the dropdown will automatically hide when the toggle link is no longer in focus. The use of `setTimeout` is important here because click events in Javascript happen after blur events, causing issues with clickable elements inside the dropdown. By introducing a slight delay, you can avoid these problems and ensure smooth functionality.

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

JavaScript getting overshadowed by other JavaScript libraries

My current CMS, Liferay, heavily relies on jQuery for various functions. Recently, I introduced a new feature to our website using fancybox. However, I realized that this new addition was causing issues with other jQuery functionalities on the page. Remov ...

What is the process for setting up FastAPI to handle server-side rendering for Vue 3?

Is it possible to achieve server-side rendering with FastAPI similar to how it's done with node.js and Vue SSR? Are Jinja2 templates or SPA the only options for rendering dynamic pages? Challenges: Avoiding SPA for better SEO Issues with excessive p ...

Retrieve all documents with a matching objectId field in MongoDB

I built an API that can fetch all data from a table, but within this table there is an object ID reference to a user. Table 1 - Story | Table 2 - User api.get('/all_stories', function(req, res) { Story.find({}, function(err, stories) { ...

Retrieving component attributes using jQuery or alternate event handlers

In my Angular2 component, I am facing an issue with using vis.js (or jQuery) click events. Despite successfully displaying my graph and catching click events, I encounter a problem where I lose access to my component's properties within the context of ...

Elasticsearch query fails to execute when encountering a special character not properly escaped

I am facing an issue with querying a keyword that includes a dot (.) at the end. While the query works perfectly on Kibana's console, it fails to execute on my application's function. The following function is responsible for creating the query b ...

Failing to retain hyperlinks with ajax

Currently, I am utilizing ajax to transmit data from a sophisticated custom field wysiwyg editor. Within this setup, the specific div with the class 'bio' is what I'm addressing. The issue arises when the data is retrieved - all the original ...

Unable to successfully upload a .docx file within OnlyOffice utilizing JavaScript

Our application has successfully integrated the OnlyOffice editor. I am currently facing an issue while trying to upload a .docx file from my PC to the OnlyOffice server for later editing. Despite sending a POST request to the server using formdata, the fu ...

I encountered an issue with passing arguments in the invoke function I redesigned

I am currently attempting to replicate the functionality of the .invoke() function. Although I can successfully call the function, I am facing difficulties when it comes to passing arguments. I have made attempts using call and apply, but unfortunately, I ...

Vue.js component unable to validate HTML input patterns

Attempting to create HTML forms with the 'pattern' input attribute has been an interesting challenge for me. When implementing this through Vue.js components, I encountered some strange behavior. Check out this fiddle to see it in action. Vue.co ...

Issue with parsing JSONP using jQuery's AJAX request

I am encountering an issue with a jQuery ajax request that I have set up. Here is the code: jQuery.ajax({ url: serverAddress+'php/product.php', type: 'GET', jsonpCallback: "callback7", dataType: 'jsonp', d ...

Exploring the money library in typescript after successfully installing it on my local machine

I've been struggling to set up a new library in my TypeScript project for the first time, and I can't seem to get it functioning properly. The library in question is money. I have downloaded it and placed it in the root of my project as instructe ...

"Revolutionize real-time data updates with Node.js, Redis, and Socket

Greetings! I am currently working on a project for my school that involves creating a "Twitter clone." My goal is to incorporate a publish subscribe pattern in order to facilitate real-time updates. One key feature users will have access to is the abili ...

Looking to bring in a non-ES6 library into VueJS without using export statements

Currently, I am faced with an interesting challenge. For a forthcoming VueJS project, we must utilize a library that is quite outdated but there is simply not enough time to redevelop it. The library is essentially a JavaScript file which consists of num ...

PHP MySQL Table with a Date Range Filter

As someone who is new to PHP, I have a question. How can I set up a date range filter? I've looked at tutorials, but they haven't worked for me. I do have some code, but it doesn't include any functions. I want to implement this in a CRUD t ...

Checking for valid zip code using a regular expression in JavaScript

Thank you for the suggestions, everyone. I have made some modifications to the script based on your advice and it appears to be functioning correctly now. <script src="jquery-1.4.2.min.js" type="text/javascript"></script> <script> $ ...

The lightbox is triggered by clicking on a different div to display its content

Great news - my lightbox is up and running! Each image on my website corresponds to a different organization, and clicking on the image opens a specific lightbox. My question is: how can I have a lightbox configured so that only the trigger image is displ ...

What could be causing the issue of being unable to connect to the NodeJS express server from any network?

Imagine having a web server running on port 3001 with the IP address 23.512.531.56 (obviously not a real one) and then switching to another network, like your neighbor's. Now, when you try entering 23.512.531.56:3001 in Chrome, why doesn't the se ...

What could be causing the issue with my css `content:` not functioning across different browsers, and how can I enhance cross-browser compatibility in all cases

Working on my first HTML/CSS project, I encountered a browser compatibility challenge. The code functions well in Firefox, IE, and Edge but fails in Chrome. Specifically, I am trying to make a button display alternating up and down arrows when clicked. Whi ...

Ways to determine if JavaScript array objects overlap

I am working with an array of objects that contain start and end range values. var ranges = [{ start: 1, end: 5 }] My goal is to add a new object to the array without any overlapping with the existing ranges, { start: 6, end: 10 } I need ...

Avoid the occurrence of the parent's event on the child node

Attempting to make changes to an existing table created in react, the table is comprised of rows and cells structured as follows: <Table> <Row onClick={rowClickHandler}> <Cell onCLick={cellClickHandler} /> <Cell /> ...