Bootstrap Vue - Prevent dropdown close on click outside - vue.js

I'm using Bootstrap-Vue and I would like my dropdown to never hide until a button calls a function. My issue is that, by default, clicking outside the dropdown or on the dropdown button hide the dropdown. My template is:
<b-dropdown
ref="dropdown"
#hide="onEditControlMenuHide"
#click.native.stop>
<b-dropdown-form>
<b-dropdown-item-button
#click="closeDropdown"
>I'm a button
</b-dropdown-item-button>
</b-dropdown-form>
</b-dropdown>
And then I have simple methods in my script:
closeDropdown() {
this.$refs.dropdown.hide()
},
onEditControlMenuHide(bvEvent) {
bvEvent.preventDefault()
},
I tried to catch the bvEvent in a function to process where the event comes from, but I find nothing in the event that differentiate hide on click outside, hide on click the dropdown button, or hide because on my custom button.
I read that it was maybe because of event bubbling, so I tried to use #click.native.stop but it doesn't work. Any help would be appreciated!

You could set a flag that is only set to true by the button's click-handler, then the hide-handler would only cancel the hide if the flag is set:
export default {
methods: {
closeDropdown() {
this._okToHide = true
this.$refs.dropdown.hide()
},
onEditControlMenuHide(bvEvent) {
if (this._okToHide) {
this._okToHide = false
} else {
bvEvent.preventDefault()
}
},
}
})
demo

<b-dropdown-item-button
#click.stop="closeDropdown"
>I'm a button
</b-dropdown-item-button>
try to use .stop modificator with click event on ur button and not on dropdown, it stops propagination event from button and should not trigger click event on dropdown.

Related

Run method when Vuetify dialog is opened

I have a v-data-table and the user can click on any row and a dialog opens. Inside on my vuetify dialog is a dropdown of data.
I want to filter this data everytime the user clicks on a row and filter out what the user clicked from the dropdown inside the dialog.
Here is my dialog:
<v-dialog v-model="edit" max-width="1200" #input="closeDialog()">
<editCompany :isEdit="true"
v-if="showEdit"
:company="selected"
:adminEdit="true"></editCompany>
</v-dialog>
You can see I'm passing in the values from the table row the user clicked.
Now, I need to use the value being passed in to filter the dropdown. The mounted event only runs once, so my logic inside of it only fires for the first row clicked.
Here is the mounted event inside of my editCompany template:
mounted: async function () {
this.filterOutResults(); //this is where i do my filtering and it works
},
Every other row the user clicks doesn't fire mounted, so I cant use that unless I can unmount the dialog when its closed.
I found how to fire an event when the dialog closes, but I cannot find a vuetify open event.
How do I run a function everytime the dialog opens so I can filter the results or how do I unmount the dialog everytime it closes, so the mounted event can run everytime? Thanks
For future references, I'll expand #mynd comment, which should be the answer:
export default {
data() {
return {
dialogVisible: false,
},
},
watch: {
dialogVisible(visible) {
if (visible) {
// Here you would put something to happen when dialog opens up
console.log("Dialog was opened!")
} else {
console.log("Dialog was closed!")
}
}
},
<v-dialog v-model="dialogVisible" max-width="1200" #input="closeDialog()">
<!-- Add code here, according to Vuetify docs -->
</v-dialog>
For further information (about constructing the v-dialog component itself), refer to the official docs
if you want to do something inside the dialog component when it's open, there is a little workaround that you can do.
<v-dialog v-model="edit" max-width="1200" #input="closeDialog()">
<editCompany :isEdit="true"
v-if="showEdit"
:company="selected"
:dialogOpen="edit"
:adminEdit="true"></editCompany>
</v-dialog>
as you see you can pass dialog's handler variable as dialog's parameter. its 'dialogOpen' in this case.
then inside editCompany component,
watch: {
'dialogOpen' :{
handler(newVal, oldVal) {
//do your stuff.
},
deep: true
},
}
So in short it will watch the variable which is controlling dialog, based on its value which mostly is true or false, you can do your operation.

TestCafe: how to set a button component on a page to a pressed state where its a click but not released?

I'm creating an automated test to test the different specs or attributes of an element (button component) but in order to do this, I have to force the button to specific states like - pressed and disabled states. I have already done it for the focus and hover states.
how to set a button element/component on a page to a pressed state where the button is clicked but not released - similar to a key down? Asking since the specs (Text color and background color) of a clicked state and a pressed state are different.
how to set a button element/component on a page to a disabled state.
Is it even possible to force element state similar to inspect/dev tools using the browser?
thanks
Currently you cannot provide the mousedown action without a further mouseup action as well as forcing an element state like in DevTools.
However, if you want to set button state to disabled, I think the ClientFunctions mechanism can help you. See the following code:
import { Selector, ClientFunction } from 'testcafe';
fixture ``
.page ``;
const btn = Selector('button');
const setDisabled = ClientFunction(() => {
btn().setAttribute('disabled', 'disabled');
}, { dependencies: { btn } });
test('test', async t => {
await setDisabled();
});

V-tooltip: Close Popover from a method

In VueJS, I'm using v-tooltip (https://github.com/Akryum/v-tooltip) for popovers.
In order to close a popup, they provide a directive called 'v-close-popover' which I can assign to a button/link inside the popover to close the popup. This works well.
However, I have a requirement where I need to close this popup from a Vue method. But I dn't know how to trigger closing of the popover from the method.
This is how you can achieve this.It will display tooltip on mouseOver event and remove on mouseLeave event.
In template->
<i
id="requiredIcon"
aria-hidden="true"
v-tooltip="{content: 'Required option is not available for this question.', show: isOpen, trigger: 'manual'}"
#mouseover="showTooltip"
#mouseleave="removeTooltip"
></i>
In Script->
data() {
return {
isOpen: false,
};
},
methods:{
showTooltip() {
this.isOpen = true;
},
removeTooltip() {
this.isOpen = false;
}
}
In case anybody else stumbles upon this issue, the v-popover component has a hide method. So if you were to place a ref on your popover component then you can access the hide method from it and call it :)

Why isn't this method getting triggered by a #keyup event?

I'm trying to focus a text field on ALT + C shortcut (in my Electron-Vue app):
Codepen: https://codepen.io/anon/pen/aqrBzq?editors=1010
The codepen uses this v-text-field custom component and as this comment on Github says, the method should be wrapped with $nextTick in order to focus this component
Need this, but doesn't work
<v-text-field
ref="filter"
#keyup.alt.67="focusFilter"
label="type here" >
</v-text-field>
...
methods: {
focusFilter(event){
this.$nextTick(event.target.focus)
}
}
This works, but is not what I need:
I also tried this code below, trying to focus it with a button, and it works, but I want to make it work with a key shortcut (for example ALT + C but more preferably CTRL + F, but for the sake of example I don't use reserved shortcut)
<v-btn #click="focusFilter()">focus</v-btn>
...
methods: {
focusFilter(event){
this.$nextTick(this.$refs.filter.focus)
}
}
When you're listening for a native event on a component you need to use the .native modifier.
So use this instead:
#keyup.native.alt.67="focusFilter"
Details here: https://v2.vuejs.org/v2/guide/components.html#Binding-Native-Events-to-Components
If you want to focus this input when alt+c is pressed and anything is focused you'd need to add an event handler to window for keyup.
I'd created a method to focus it under the right circumstances like:
methods: {
listenForFocusFilterShortcut (event) {
if (event.keyCode === 67 && event.altKey) {
this.$refs.filter.focus()
}
},
}
Then, add a created hook and attach this callback to the window when there's a keyup event.
created () {
window.addEventListener(
'keyup',
this.listenForFocusFilterShortcut
)
},
Then, remove the event listener when the component is removed:
destroyed () {
window.removeEventListener(
'keyup',
this.listenForFocusFilterShortcut
)
}

Open a modal and fetch data from server on click of a button outside the component

I am very new to Vue.js. In fact I just started today.
I have a problem.
Let's say I have button in a table somewhere in dom.
<table>
<tr><td><button v-on:click="showModal">Show</button>
</table>
Now I have a modal box outside of the scope of the button.
This button is inside a component of itself and the modal box has a component of itself too.
I am passing in an id with this button, and what I want to do is:
Fetch the id on button click
Show the record fetched in the modal and then finally perform some action on it
My problem is I am unable to get a method in the Modal component (that does a http request and fetches and renders the data) to trigger by the click event of this button.
The button and the modal has no relationship, they are not parent/child.
In modal component trigger method to fetch data by component ready state:
ready: function() {
this.getAllTheDataYouNeed();
},
You may use another life cycle hook:
https://vuejs.org/guide/instance.html#Lifecycle-Diagram
An option was to add the event broadcast in the common ancestor of both the components.
Like this:
var main = new Vue({
el: 'body',
components: {
zmodal : zmodal,
showhidebtn : showhidebtn,
},
methods: {
showModal: function (currentId) {
this.$broadcast('openModalBox', currentId);
}
}
});
Add an event listener in 'zmodal' and call this function showModal from on click event of 'showhidebtn' component.
It is working but now I have a set of codes outside the components that have to be triggered for this to work.
I wonder if there is a better way to do this.