Extending vuetify v-btn component, adding custom click event - vue.js

I am trying to create component which would extend v-btn in such a way that every time I click a button, it should emit short beep, and disable the button for 5 seconds.
It would be ideal for the button to change color while disabled.
This is a problem, since color is a property, and I can't overwrite it's value...
Also, when I try to invoke super.click(e), I get an error.
You can check example here: https://codesandbox.io/s/elegant-glade-pnhqx

Your Btn component should just "use" v-btn rather than extending it.
v-bind="$attrs" is to copy any <btn>'s attribute onto <v-btn>.
#click event is captured and reemited as-is after doing what needs to be done
See https://codesandbox.io/s/immutable-paper-w1wck?file=/src/components/Btn.vue:41-56

Related

How to prevent selection of a SortableJS item when clicking on one of its child elements?

The Issue
I'm using SortableJS to build a draggable tree component. Which means each of my sortable-items has a toggle-arrow as a child element that opens and closes a sub-tree (if there is one).
I'm attempting to use stopPropagation() to prevent the selection of the parent sortable-item if the toggle-arrow is clicked, but it's not working.
It looks like this when closed:
And looks like this when open:
The blue highlight you see in the open state (the second image) is the styling I've chosen for the selectedClass option when using the multiDrag plugin.
This is illustrating that when I click on the toggle-arrow it results in the parent sortable-item being selected.
I don't want this to happen.
The Code
The code for an item in my SortableJS tree component looks like so (using Vue.js, and Pug syntax):
div.sortable-item
div.content
div.toggle-arrow(#click.stop="toggleTree($event)")
div.icon
div.title
div.sub-tree
And then I've got a handler for the #click binding on my toggle-arrow element:
toggleTree = function($event) {
$event.stopPropagation()
/// Code for handling the sub-tree toggling goes here.
/// The sub-tree toggling itself works just fine.
}
You can see that I'm declaring #click.stop as the event binding, which should stop the click event from bubbling up from the toggle-arrow child element, but it's not working.
I'm even attempting to use $event.stopPropagation within the handler. But, the event seems to continue to bubble, and thus the parent sortable-item element ends up in a selected state.
I've also tried declaring #click.native.stop as the event binding, but it simply prevents my toggleTree method from firing at all. I'm assuming there's another event handler somewhere within SortableJS that's interfering with the #click.native.stop binding.
Questions
How do I stop propagation of an event when a child element of my sortable-item is clicked?
How is selection handled by the multiDrag plugin? I dug through the code and saw that the select event is fired within the handler of the drop event of the sortable-item, but I'm confused by that. Why is the drop event handler being used to toggle selection of a sortable-item?
Thanks in advance for any light you may be able to shed on this.
Wrong Event
Looking at the source of SortableJS it seems that the event you want to stop from bubbling is not the click event, but rather the mouseup event.
The "Stuck" Drag Item Problem
As indicated in the comments of this answer, stopping propagation on the mouseup event causes an issue where the drag is started unintentionally, and the sortable-item becomes "stuck" to the pointer.
It seems that the "drag initiation" is triggered by either pointerdown, mousedown, or touchstart events, depending on the device.
It can be safely assumed that the pointerdown event is the one that does the triggering according to caniuse.com.
The Solution
So the actual way to solve this is to use a #pointerdown.stop event binding to trigger your toggleTree method without triggering either selection of the sortable-item, or the unintentional drag initiation.
div.sortable-item
div.content
div.toggle-arrow(#pointerdown.stop="toggleTree($event)")
div.icon
div.title
div.sub-tree
Change
div.toggle-arrow(#click.stop="toggleTree($event)")
to
div.toggle-arrow(#click.native.stop="toggleTree($event)")
If all you did in toggleTree was stopPropagation, you could have changed it to:
div.toggle-arrow(#click.native.stop)
Docs.
In short, you're currently stopping propagation on any emitted clicks from the child component (a.k.a. custom Vue event, which doesn't actually need propagation stopped as it doesn't bubble by default). What you want to do is call event.stopPropagation() on the native click event.
An alternative would be to use:
div.toggle-arrow(#click.native="toggleTree($event)")
... and call .stopPropagation() inside toggleTree. Which is precisely what .stop modifier does.

strange behavior when trying to re-render data inside slot in vue

I am getting strange behaviour when trying to dynamically update the content of a slot in Vue with Vuetify. I'm sure this is just a function of misunderstanding how slots work.
I have a slot in a custom component, like so:
<template #selectButtons="slotProps">
<v-icon #click="dropToggle(slotProps.player)"
:color="dropColor(slotProps.player)"
class="mr-5"
>
fas fa-skull-crossbones
</v-icon>
</template>
When the user clicks on the icon, it is meant to toggle the icon to different colors.
I cannot seem to get dropColor to fire on each click consistently, HOWEVER, the weird part is, if I make some change inside the <v-icon> component, like say I just add {{dropColor(slotProps.player)}} inside the v-icon tags, then all of a sudden the code will work.
But then if I do a full refresh of the page, it stops working. Then I delete that code and put it back in, then it works again!
I have tried forceUpdate and keys on the v-icon tag.
Would appreciate any help
You are trying to pass function dropColor(slotProps.player) as props. The better idea is to replace function to an object or variable and change that object/variable within method dropToggle(slotProps.player) after #click event is firing .

Trigger a button click from clicking another button in vuetify project?

I need clicking on one button to activate a click function on a different button. I expected to be able to use a ref prop on the button to achieve this but instead I get a 'Cannot read property '$refs' of null' console error.
<v-btn ref="modalButton" #click="modal">Open Modal</v-btn>
<v-btn #click="this.$refs.modalButton.click()">Click other button</v-btn>
Apparently this is because the component isn't created yet but I'm truly confused about what that means and how to solve the problem.
Please note the click has no '()'
<v-btn ref="modalButton" #click="modal">Open Modal</v-btn>
<v-btn #click="$refs.modalButton.$el.click">Click other button</v-btn>
Put "this.$refs.modalButton.click()" into a function - you can't refer to the modalButton that way in the HTML.
Although, if the visibility of your modal is tied to a data property, I don't know why you can't just change the data property directly with both buttons.
If you want to do something when another thing happens, try to use something called event bus. I solve a lot of problems implementing that.
Here is an example:
https://alligator.io/vuejs/global-event-bus/
Btw: If your problem is that the other component has not been created at the render moment, you can solve it calling a function on the #click event, then when you click it, you are going to call the function that is going to be called when everything in the DOM has been rendered. At least that is the way that I solve that kind of problems.

VueJS 2 - Default click event on component

Is it possible in VueJS to have a default click event on a custom component?
E.g. we have built a component called editable. Now on click, we always want it to fire the same function, no matter where we call that component.
<editable #click="doSomething" ...></editable>
Can I define that somewhere in the JS side?
In case of custom component, you need to bind to native event:
<editable #click.native="doSomething" ...></editable>
For documentation, refer to Vue.js docs here.

Why VueJs introduce .native Event modifier ? What are the use case of this? - Vue.js

I din't get any docs for native event modifiers. I have seen some where like this:
<router-link #click.native="pressThis()"> Press here </router-link>
what is the use of native modifier on router-link click event.
and what other use case native modifier can have ?
You can override Vue events in custom components. For instance, you might have a list component that once you click an item you call this.$emit('click', selectedItemData), and that will emit the click event to the parent component that is watching that.
However, sometimes you really want to bind to the native HTML/DOM event listener element.addEventListener('click', callThisMethod), and that's the use of .native. Also, make a note that it will handle cleaning the event listener once your component gets destroyed just like a non-native event.
In sum: use .native when you need the 'raw' event from DOM.