Closed YuqiaoS closed 1 year ago
@YuqiaoS No, it binds slot scope (values that are passed to slot scope), not all data.
This isn't clear at all. You should add doc to explain what the syntax means.
But that doesn't tell you that there's the "on" property that the slots pass to the parents that contains some built in listeners that you don't know of.
Scoped slot passes things that are passed by component
All v-tooltip slots aren't scoped, you can't get anything from them via this method
And you don't know what component passes to the slot if you don't read the source code, I agree that there should be explained what data is passed, probably in slots
section
@sh7dm activator
slot is (can be) scoped
Example code doesnt work right away. All examples are using same structure and docs are not helping as usual.
This has also confused me. I'm not sure how to create & use tooltips in my own components. Seems like a tooltip should have a default slot for the main component, and a named slot for the tooltip itself. The documentation doesn't really have much explanation of how it works.
this v-on="on"
confuses me so so much.
I have been digging Vuejs Documentation for a long time and no luck. I don't know what it means.
I thoughtv-on:click
is the common usage, or @click
.
So, what the heck is v-on="on"
? what is on
?
@yuminatwca if you look at at the example you will see that on
is a prop passed in from the activator. all v-on="on"
is doing is bind that on
prop to the component. on
itself is all of the event listeners passed from the activator.
I have been digging Vuejs Documentation for a long time and no luck
Also this can be reported in vue docs repo
The question is not (I think) what "v-on" means; that's standard Vue. The question is why do I have to pass something called "on" around just to get a tooltip. My component doesn't have anything called "on", so what is the "on" object, why is it needed, is that name part of the API or is it arbitrary, is it useful to me or is it just boilerplate? These are the questions at hand I think.
According to vuejs documentation, a new syntax has been introduced since 2.4.0+:
<!-- object syntax (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
But, what is confusing is v-on={ on }
.
OK, here is the question: on what? on which event triggered ?
The question is not (I think) what "v-on" means; that's standard Vue. The question is why do I have to pass something called "on" around just to get a tooltip. My component doesn't have anything called "on", so what is the "on" object, why is it needed, is that name part of the API or is it arbitrary, is it useful to me or is it just boilerplate? These are the questions at hand I think.
Accurate.
I attempted to implement a date picker yesterday, adhering to the samples provided, and it was breaking on this mysterious "on" construct; only guessing as to why, I decided it must be time to drag my vue and vuetify packages up to latest versions. (Several hours of dependency mazes later) I got it working.
so what is the "on" object, why is it needed, is that name part of the API or is it arbitrary, is it useful to me or is it just boilerplate?
Fwiw, it does evidently only function with v-slot:activator="{ on }"
and v-on="on"
explicitly; when I tried v-slot:activator="{ onit }"
and v-on="onit"
, it would not function.
Up until I have seen this, I was thinking vuetify makes readable codebase ;)
Far better to write it like this if possible
<v-tooltip bottom v-for="(link, index) in project.links">
<v-btn :href="link.url" :key="index" class="mx-3" icon
slot="activator" style="color: var(--primary-color)" target="_blank">
<v-icon size="50px">{{ link.icon }}</v-icon>
</v-btn>
<span>{{link.tip}}</span>
</v-tooltip>
sure but slot="activator"
won't work anymore in vuetify 2.0
And it adds an extra html element which can sometimes break the layout
If we're looking at this syntax:
<v-dialog v-model="visible">
<template v-slot:activator="{ on }">
<v-btn v-on="on">
and we look at the following
Now when we use the \<todo-list> component, we can optionally define an alternative \<template> for todo items, but with access to data from the child
<todo-list v-bind:todos="todos"> <template v-slot:todo="{ todo }"> <span v-if="todo.isComplete">✓</span> {{ todo.text }} </template> </todo-list>
v-on
api<!-- object syntax (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>
Contains parent-scope v-on event listeners (without .native modifiers). This can be passed down to an inner component via v-on="$listeners" - useful when creating transparent wrapper components.
genActivator: function genActivator() {
var _this3 = this;
if (!this.hasActivator) return null;
var listeners = this.disabled ? {} : {
click: function click(e) {
e.stopPropagation();
_this3.getActivator(e);
if (!_this3.disabled) _this3.isActive = !_this3.isActive;
}
};
if ((0, _helpers.getSlotType)(this, 'activator') === 'scoped') {
var activator = this.$scopedSlots.activator({ on: listeners });
this.activatorNode = activator;
return activator;
}
return this.$createElement('div', {
staticClass: 'v-dialog__activator',
class: {
'v-dialog__activator--disabled': this.disabled
},
ref: 'activator',
on: listeners
}, this.$slots.activator);
}
Expose the on
event listeners object from the parent v-dialog
component's activator slot to the child template. Using the v-on object syntax bind all the fields of the on
event listeners object to the v-btn
component's events. When the v-btn
component is clicked, the function associated with the click field of the on
event listeners object will be called, causing the v-dialog component to become visible.
The combination of the following
v-slot:activator="{ on }"
is exposing the object on
via object destructuring.
on
is itself an object and not something else.on
is coming fromv-on="on"
is leveraging the new v-on object syntax to automatically assign events on the v-btn
component to functions associated with fields of the on
objectIf we rearrange the syntax slightly it is a bit more intuitive what is going on as it only requires knowledge of how slot scopes can pass data to their children by automatically communicating that on
is an object with a click
field that is getting associated with the v-btn
click event.
<v-dialog v-model="visible">
<template v-slot:activator="{ on: { click } }">
<v-btn v-on:click="click">
we rearrange the syntax slightly it is a bit more intuitive what is going on as it only requires knowledge of how slot scopes can pass data to their children by automatically communicating that
on
is an object with aclick
field that is getting associated with thev-btn
click event.<v-dialog v-model="visible"> <template v-slot:activator="{ on: { click } }"> <v-btn v-on:click="click">
This would also help with using these slot scopes with children that are not native elements:
<v-dialog v-model="visible">
<template v-slot:activator="{ on: { click } }">
<custom-element v-on:click.native="click">
Offtopic, but kinda related since this thread is caused by complexity and confusion...
Is it super crazy to desire a simple version of tooltips?
<v-tooltip tooltip="Text">
<v-icon>home</v-icon>
</v-tooltip>
Simple text content on hover is, probably, the most common usage of a component.
Actually if you use the 'v-tooltip' npm module at https://www.npmjs.com/package/v-tooltip, it has even simpler syntax because it's just a directive:
<v-icon @click="logOut"
v-tooltip='"Log out"'>
logout
</v-icon>
It's not totally material-design but you can style it pretty well.
@garyo that is a nice example of how a simple tooltip could be declared! Yet, I'd like to stick to a chosen library as much as possible. Standalone packages tend to have their own merits (in v-tooltip case it is unjustified bundle weight).
So, hopefully, tooltip API will be simpler one day. Maybe it is worth opening a new thread and start working towards API simplification. Even though this conversation seems to go in circles - #2961
💀 Important to note the example :
<v-dialog v-model="visible"> <template v-slot:activator="{ on: { click } }"> <v-btn v-on:click="click">
uses "click"; it is not same:same it would not work on a phone or device without a mouse potentially creating a poor inconsistent across device user experience ( ... so hopefully that's what you wanted). ❤🐭 cheers!
@elasticdotventures What exactly doesn't work? https://codepen.io/anon/pen/voYNwb
After reading all the messages above, I still have some confusion 😕 . I have two nested elements both having activators:
<v-card>
<v-card-text>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-layout align-center row wrap mx-2 v-on="on">
<!-- a bunch of v-flex here that I removed for ease of reading -->
<v-flex pl-5 md12 lg1>
<v-dialog v-model="dialog" max-width="344">
<template v-slot:activator="{on}">
<v-btn outlined class="mr-2 blue accent-1" v-on="on">Rate</v-btn>
</template>
<RateComponent :calculator="calculator" v-bind:dialog.sync="dialog" />
</v-dialog>
</v-flex>
</v-layout>
</template>
<span>Click RATE button on the right to rate this calculator</span>
</v-tooltip>
</v-card-text>
</v-card>
So everything is under <v-tooltip>
with an activator on
that is bound to the v-on
of <v-layout>
, which includes the <v-dialog>
also having an activator on
bound to the v-on
of <v-btn>
under the very same <v-layout>
. Now don't get me wrong, everything is working as it should be; the dialog is not shown on hovering the <v-layout>
, nor the dialog has the tooltips displayed on hovering. But I am not sure why it works as it should. My instinct says "do not touch if it ain't broke" but my curiosity keeps poking my head 😃
@mcanyucel For nested activators it's better to name them somewhat context-wise, like
<v-tooltip>
<template v-slot:activator="{ on: tooltip }">
<v-layout v-on="tooltip">
<v-dialog>
<template v-slot:activator="{ on: dialog }">
<v-btn v-on="dialog">Rate</v-btn>
</template>
</v-dialog>
</v-layout>
</template>
<span>Tooltip text</span>
</v-tooltip>
As for why your example is working, consider this example:
const on = {
click: () => {
console.log('Outer scope')
}
}
on.click() // --> 'Outer scope'
const inner = () => {
const on = {
click: () => {
console.log('Inner scope')
}
}
on.click()
}
inner() // --> 'Inner scope'
on.click() // --> 'Outer scope'
Perhaps I don’t understand how to use it. The screen is blank. Nothing appears on the screen; no button, no press enter, no “click me” just a blank screen.
So I went into my browsers webconsole; by pressing CTRL-SHIFT+J and I saw a big message in red:
vue.js:634 [Vue warn]: Error in beforeCreate hook: "Error: Vuetify is not properly initialized, see https://vuetifyjs.com/getting-started/quick-start#bootstrapping-the-vuetify-object"
Realizing what the problem was – I added
import Vuetify from 'vuetify/lib' Vue.use(Vuetify);
to the “JS” section; and it worked! So I think the problem is someplace in the codepen template?
/🚀
Sent from Mail for Windows 10
From: Jacek Karczmarczyk Sent: Thursday, July 18, 2019 3:21 PM To: vuetifyjs/vuetify Cc: elasticdotventures; Mention Subject: Re: [vuetifyjs/vuetify] [Documentation] v-slot:activator="{ on }"(#6866)
@elasticdotventures What exactly doesn't work? https://codepen.io/anon/pen/voYNwb — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
That was 1.x example, here is updated to 2.0 https://codepen.io/jkarczm/pen/oNvBrar You need to press tab twice though, because of some other bug
How can I use this v-on activator (for v-menu) for hover events ??
This is confusing as hell. To click event, this "syntax" vuetify team has choosen works out-of-box.. but when we need hover, this is complicated, when this should not be.
@aislanmaia you can use the open-on-hover
prop on v-menu
.
On the larger debate, I can appreciate both sides. On one hand, having an intuitive syntax is fantastic and is part of what makes working with Vue so great; on the other you have syntax that is a little cryptic but elegant and flexible enough for it to be used consistently throughout Vuetify.
Ultimately, we live in an ecosystem of abstractions where you don't have to understand everything to accomplish your goal. Stop to consider how many other dependencies you use without understanding what goes on under the hood.
Therefore, in my opinion I wouldn't change the syntax. That said, while I don't feel explaining this is necessary for consumption, for the majority of users it is at the very least a repeating pattern that Vuetify is a proponent of. I think we could help users of Vuetify by providing a short breakdown of this somewhere in the documentation.
There is no example of how to capture the events to do our own actions with this syntax. I would guess we should do something like:
<v-tooltip bottom>
<template #activator="{ on }">
<v-btn icon v-on="{ ...on, click: openSettings }">
<v-icon>mdi-settings</v-icon>
</v-btn>
</template>
<span>Settings</span>
</v-tooltip>
or
<v-tooltip bottom>
<template #activator="{ on }">
<v-btn icon v-on="on" @click="openSettings">
<v-icon>mdi-settings</v-icon>
</v-btn>
</template>
<span>Settings</span>
</v-tooltip>
But it looks a bit weird. Also, only my second example allows setting modifiers on the click
event.
My 2 cents on all the complains about is that Vue came to save us from the boilerplate that we need to write in React, Angular.... So the selling point of Vue, Vuetify was Fast to learn and fast to write an app
. However with this kind of syntax it's becoming very hard to understand and take longer to add a simple tooltip. Why not make a simple tooltip directive that 90% of use use all the time. And have the Tooltip delux
component that allow you to have extra cheese, french fries, and sauce...
I think it's time for me to go on my own and write my own beautiful, simple, and powerful framework! I will call it vue-ez-fy
https://github.com/vuetifyjs/vuetify/issues/9610
For dialogs and menus we still need it
BTW i think in other places (lists?) we also use v-bind="attrs"
, so in docs it should mentioned as well
how to export the click function to use on my v-model="dialog" and patterns components
<template v-slot:activator="{ on: { click }, value }"> <v-btn color="primary" dark class="mb-2" @click="click">Nuevo {{ value }} {{ dialog }} {{ title }}</v-btn> </template>
sure but
slot="activator"
won't work anymore in vuetify2.0
so what is replaces it cus i used in my project and seems not work
<v-tooltip bottom> <template #activator="{ on }"> <v-btn icon v-on="on" @click="openSettings"> <v-icon>mdi-settings</v-icon> </v-btn> </template> <span>Settings</span> </v-tooltip>
But it looks a bit weird. Also, only my second example allows setting modifiers on the
click
event.
I had to go through this entire thread to find the answer to my question: What is the correct syntax for getting a click event fired on a button that has a v-tooltip. Whew! And I still do not understand why I need any of that "on" stuff. This why I have so little hair left. Thanks to @pdcmoreira for figuring out that you just need to add a @ click.
@pdcmoreira that's right. I did exactly that, but instead of using a single click I used the whole $listeners in a wrapper fashion way. it results in something like the following:
<template v-slot:activator="{ on }">
<my-comp v-on="{...on, ...$listeners}" />
</template>
It makes sense if you think that are both objects:)) The issue raise when you forget that "on" is an object.
@Dinuz sure, but that's only if you want to pass all the listeners from parent to child.
this docs explanation can be short answer for all question about slots and its details :
I'm using typescript in vscode with vue-3 and vuetify next.
The sample code for a dialog on the vuetify site is:
<template>
<div class="text-center">
<v-dialog
v-model="dialog"
width="500"
>
<template v-slot:activator="{ on, attrs }">
<v-btn
color="red lighten-2"
dark
v-bind="attrs"
v-on="on"
>
Click Me
</v-btn>
</template>
...
</v-dialog>
</div>
</template>
But I kept getting a ts compile error:
Property 'on' does not exist on type '{ isActive: boolean; props: Record<string, any>; }'.
Property 'attrs' does not exist on type '{ isActive: boolean; props: Record<string, any>; }'.
Thanks to some of the posts above, I was able to modify the code and get it working. The key line is to change:
<template v-slot:activator="{ on, attrs }">
to:
<template v-slot:activator="{ isActive: on, props: attrs }">
I'm just paying it forward in case this helps anyone else.
Thank you folks on this thread!
自动回复:我已收到邮件,谢谢!!
@robinzimmermann Look at the examples on https://next.vuetifyjs.com/en/components/dialogs/
Thanks @KaelWD!
And thank you for not also throwing in "RTFM!"
Is this still relevant? It seems to be all examples have been replaced with props
instead, and v-on
is no longer referred.
https://vuetifyjs.com/en/components/tooltips#usage
So I'm guessing that the activator slot in the component binds the data object from the render function so that its available in the parent scope. The data object contains an
on
property which includes the event listeners.It'd be nice for the doc to provide some pointers to the logic and syntax used. A brief comment in the activator slot description with a link to the below url would be nice.
https://vuejs.org/v2/guide/render-function.html#The-Data-Object-In-Depth
Originally posted by @YuqiaoS in https://github.com/vuetifyjs/vuetify/issues/6823#issuecomment-476560266