I have a dropdown-button
component which has a click lister. The button has some text and icon. The click event is triggered if we click the button carefully on the outline and not on the text or icon. Here is my component:
<template lang="html">
<div>
<button class="button dropbtn" @click="toggleDropdown">
<span>{{ name }}</span>
<span class="icon"><i class="fa fa-caret-down"></i></span>
</button>
<div v-show="visible" class="dropdown-content is-primary-important">
<slot>
</slot>
</div>
</div>
</template>
<script>
export default {
props: ['name'],
data: function() {
return {
visible: false
}
},
mounted: function() {
this.hideDropdownOnClick();
},
methods: {
toggleDropdown: function() {
// trigged on click of the button
// make the dropdown visible
console.log("toggling dropdown");
this.visible = !this.visible;
},
hideDropdownOnClick: function() {
window.onclick = (event) => {
console.log(event.target);
if (!event.target.matches('.dropbtn')) {
console.log("here", this.visible);
this.visible = false;
}
}
}
}
}
</script>
<style lang="css">
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
position: absolute;
background-color: #fff;
min-width: 140px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
padding: 12px 16px;
text-decoration: none;
display: block;
}
</style>
I feel that I am missing something very basic here, can someone help me with this? Thanks.
Edit
It seems like a bug with the browser as the answer to this question says: Button element not firing click event when clicking on button text and releasing off it (but still inside the button)?
I have a dropdown-button
component which has a click lister. The button has some text and icon. The click event is triggered if we click the button carefully on the outline and not on the text or icon. Here is my component:
<template lang="html">
<div>
<button class="button dropbtn" @click="toggleDropdown">
<span>{{ name }}</span>
<span class="icon"><i class="fa fa-caret-down"></i></span>
</button>
<div v-show="visible" class="dropdown-content is-primary-important">
<slot>
</slot>
</div>
</div>
</template>
<script>
export default {
props: ['name'],
data: function() {
return {
visible: false
}
},
mounted: function() {
this.hideDropdownOnClick();
},
methods: {
toggleDropdown: function() {
// trigged on click of the button
// make the dropdown visible
console.log("toggling dropdown");
this.visible = !this.visible;
},
hideDropdownOnClick: function() {
window.onclick = (event) => {
console.log(event.target);
if (!event.target.matches('.dropbtn')) {
console.log("here", this.visible);
this.visible = false;
}
}
}
}
}
</script>
<style lang="css">
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
position: absolute;
background-color: #fff;
min-width: 140px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Links inside the dropdown */
.dropdown-content a {
padding: 12px 16px;
text-decoration: none;
display: block;
}
</style>
I feel that I am missing something very basic here, can someone help me with this? Thanks.
Edit
It seems like a bug with the browser as the answer to this question says: Button element not firing click event when clicking on button text and releasing off it (but still inside the button)?
Share Improve this question edited May 23, 2017 at 10:31 CommunityBot 11 silver badge asked Apr 14, 2017 at 12:17 aksaks 9,49111 gold badges52 silver badges81 bronze badges 4 |4 Answers
Reset to default 19Adding this CSS rule fixes the issue for me:
span {
pointer-events: none;
}
When You click in span its toggled twice:) once by toggleDropdown method, second by windows onclick handler.
here is working example: jsfiddle
<template id="tmp">
<div>
<button class="button dropbtn" @click="toggleDropdown">
<span>{{ name }}</span>
<span class="icon"><i class="fa fa-caret-down"></i></span>
</button>
<div v-show="visible" class="dropdown-content is-primary-important">
<slot>
</slot>
</div>
</div>
</template>
<div id="x">
<tmp name="my name">
<span>toggle me!</span>
</tmp>
</div>
Vue.component('tmp', {
template: '#tmp',
props: ['name'],
data: function() {
return {
visible: false
}
},
mounted: function() {
this.hideDropdownOnClick();
},
methods: {
toggleDropdown: function() {
// trigged on click of the button
// make the dropdown visible
console.log("toggling dropdown");
this.visible = !this.visible;
}
}
});
new Vue({
el: '#x',
data: function(){
return {
name: 'myName'
}
}
});
edit: if you don't want to use clickaway here is small directive to detect clicks outside of element:
var VueClickOutSide = {
bind: function(el, binding, vNode) {
var bubble = binding.modifiers.bubble;
var handler = function(e) {
if (bubble || (!el.contains(e.target) && el !== e.target)) {
binding.value(e);
}
}
el.__vueClickOutside__ = handler;
document.addEventListener('click', handler);
},
unbind: function (el, binding, vNode) {
document.removeEventListener('click', el.__vueClickOutside__);
el.__vueClickOutside__ = null;
}
};
You just have to register that directive:
Vue.directive('click-outside', VueClickOutSide)
And use it in template:
v-click-outside:delay="hideDropdownOnClick"
You can use vue-clickaway to hide dropdown when click outside :
$ npm install vue-clickaway --save
import { mixin as clickaway } from 'vue-clickaway';
export default { mixins: [ clickaway ], ... the rest of your code ...
You put
v-clickaway="visible = false"
in your root div of yourdropdown-button
component.
On click you show and immediately hide list. You click text or icon (they are "span"),
this.visible = !this.visible;
then code goes to window.onclick where
if (!event.target.matches('.dropbtn'))
and your spans dont have this class. So you set
this.visible = false;
Change check to
if (!event.target.closest('.dropbtn'))
chrome
it is not working! – aks Commented Apr 14, 2017 at 12:30