I'm new to Vue.js and I hope with your help to understand scoped slots...
I would like to optimize my code, the tooltip must be visible on hover only if the label has more than 10 characters (or any other condition).
This works, but it is not optimized:
<v-btn>
<v-tooltip right v-if="slot.label.length > 20">
<template v-slot:activator="{on}">
<span class="text-truncate ml-1 mr-1" v-on="on">
{{slot.label}}
</span>
</template>
<span>{{slot.label}}</span>
</v-tooltip>
<span v-else class="text-truncate ml-1 mr-1">
{{slot.label}}
</span>
</v-btn>
I think the easiest way to achieve the desired effect without duplication is to use the disabled prop of v-tooltip.
new Vue({
el: '#app',
data () {
return {
slot: {
label: 'Label'
}
}
}
})
<link rel="stylesheet" href="https://unpkg.com/vuetify#1.5.16/dist/vuetify.css">
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#1.5.16/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-btn>
<v-tooltip right :disabled="slot.label.length < 10">
<template v-slot:activator="{on}">
<span class="text-truncate ml-1 mr-1" v-on="on">
Button: {{ slot.label }}
</span>
</template>
<span>Tooltip: {{ slot.label }}</span>
</v-tooltip>
</v-btn>
<v-btn #click="slot.label = 'Label'">Short</v-btn>
<v-btn #click="slot.label = 'Label label'">Long</v-btn>
</v-app>
</div>
The downside of this approach is that it still creates the tooltip even if it's disabled. The overhead isn't significant but if there are going to be a lot of tooltips then that might be a consideration.
There are various other ways to approach this but I can't think of any that are particularly simple. You could use a render function. That would allow you to write exactly what you want without any duplication but at the expense of needing to maintain a render function.
Sometimes you may want to show the tooltip when the underlying element is disabled. For eg: If a user has used all the resources in his account and then we need to ask the user to buy more resources. In such time insert an extra div and then add v-on onto to it.
<v-tooltip bottom :disabled="!noCandies">
<template v-slot:activator="{ on, attrs }">
<div v-on="on"> <!-- CREATE A DIV AND ADD V-ON HERE-->
<v-btn :disabled="noCandies" small class="mt-1" #click="useCandy">
Use candy
</v-btn>
</div>
</template>
<span>Buy more candies</span>
</v-tooltip>
Related
I have a combobox:
<v-combobox
v-model="selectedCategories"
:items="attributeCategories"
item-text="name"
item-value="id"
label="Category"
multiple
chips
v-on:blur="changeCategory(selectedCategories)"
></v-combobox>
It's rendered like this:
I would like to add an x on each badge, so I can quickly remove it.
Is there a setting that I need to turn on?
In regular input type text, I can just add these props
clear-icon="mdi-close-circle"
clearable
The VComboBox's selection slot enables customizing the rendering of the selections. You could add a VChip with a VIcon child that re-selects the item when clicked (thus toggling its selection, and removing the chip):
<v-combobox ⋯ chips>
<template v-slot:selection="{ attrs, item, parent, selected }">
<v-chip v-bind="attrs" :input-value="selected">
<span class="pr-2">
{{ item.name }}
</span>
<v-icon small #click="parent.selectItem(item)"> $delete </v-icon>
</v-chip>
</template>
</v-combobox>
demo
You can simply achieve that by adding the <v-icon> inside <v-chip> in the <v-slot> template. I just created the working demo with the same data set you have in the screenshot mentioned above.
Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
items: ['Weather', 'Geo Location', 'Device', 'Date and Time', 'Product'],
model: ['Weather', 'Geo Location', 'Device', 'Date and Time', 'Product']
})
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.5/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.5/dist/vuetify.min.css"/>
<div id="app">
<link rel="stylesheet" href="https://unpkg.com/#mdi/font#6.x/css/materialdesignicons.min.css"/>
<v-app id="inspire">
<v-container fluid>
<v-combobox
v-model="model"
:items="items"
label="Category"
multiple
small-chips
>
<template v-slot:selection="{ item, parent }">
<v-chip
label
small
>
<span class="pr-2">
{{ item }}
</span>
<v-icon
small
#click="parent.selectItem(item)"
>
$delete
</v-icon>
</v-chip>
</template>
</v-combobox>
</v-container>
</v-app>
</div>
There is a chips props your <v-combobox...> - so depends on Vuetify version there are two props you should add:
deletable-chips for Vuetify 2 according to docs
<v-combobox
...
chips
deletable-chips
/>
closable-chips for Vuetify 3 according to docs
<v-combobox
...
chips
closable-chips
/>
Also there is clearable prop that adds clear button on the right that clear all chips via one click (works for both Vuetify versions):
<v-combobox
...
clearable
/>
I have added code for v-tooltip but it doesn't display when I hover the combobox , do you see mistakes or in the order of the code, let me know, please.Thanks .
<template>
<div>
<v-tooltip top>
<template v-slot:activator="{ on, attrs }">
<v-combobox
bottom
chips
:items="items"
label="Choose videos"
multiple
/>
</template>
<span>Left tooltip aaaaaaaaaaaaaaaaaaaaaaa</span>
</v-tooltip>
</div>
</template>
When I hover the combobox , nothing happens
You're not applying the activator slot attributes.
Secondly, the combo box creates a parent element that wraps the input that the activator attributes bind to.
This breaks the tooltip, causing it to only trigger when the box input is clicked on.
What you need to do is also wrap your combo box in a div and apply the activator to the div like this:
<template>
<div>
<v-tooltip top>
<template #activator="{on, attrs}">
<div multiple v-on="on">
<v-combobox
bottom
chips
:items="items"
label="Choose videos"
v-bind="attrs"
/>
</div>
</template>
<span>Left tooltip aaaaaaaaaaaaaaaaaaaaaaa</span>
</v-tooltip>
</div>
</template>
This same fix also applies to other Vuetify elements such as v-select which also create their own parent elements.
<VRadioGroup :multiple="multiple" v-model="radioGroup">
<VRadio
v-for="(item, index) in options"
:key="index"
:label="item.text"
:value="item.value"
>
</VRadio>
</VRadioGroup>
I got something like this.
Question 1) I want user to be able to select all of them or as many as he wants. Looks like :multiple="true" or multiple doesn't work. I can only select one. I should also be able to unselect any of them.
Question 2) beside each v-radio, I want to have its name, button and icon. I tried the following thing(All I could find was v-radio has a label slot. I tried this:
<template slot="label" slot-scope="data">
{{ data.item.text }}
<VBtn #click="removeRadioButton(item.value)" ripple
><BaseIcon name="minus-circle" /> </VBtn
>
</template>
I put this between VRadio tags. Looks like each of them has a button and icon, but it gives me error. (item of undefined). seems like data in slot-scope is undefined.
Answer 1:
It is simple. You can change the type radioGroup to an array.
It will work.
<div id="app">
<v-app id="inspire">
<v-container fluid px-0>
{{radioGroup}}
<v-radio-group
v-model="radioGroup"
multiple=true>
<v-radio
v-for="n in 3"
:key="n"
:label="`Radio ${n}`"
:value="n"
></v-radio>
</v-radio-group>
</v-container>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
radioGroup: []
}
},
})
Note: But For multiple selections, you shouldn't use radio buttons. Go for Checkbox.
Answer 2:
Issue In your code: You're looping on the radio button.
If you want some different text on before all radio buttons then you need to loop on a div which will contain the text and icons.
<div id="app">
<v-app id="inspire">
<v-container fluid px-0>
{{radioGroup}}
<v-radio-group
v-model="radioGroup"
multiple="true">
<div
v-for="n in 3"
:key="n"
>
<span class="d-inline">
{{n}}
</span>
<v-radio
class="d-inline"
:label="`Radio ${n}`"
:value="n"
></v-radio>
<span>
icon here
</span>
</div>
</v-radio-group>
</v-container>
</v-app>
</div>
The weekly calendar does not display events properly. Even the snippet code from the https://vuetifyjs.com/en/components/calendars also render me an empty calendar. I wanted to use the feature but I could not find what went wrong with the following snippet.
I noticed a typo in template v-slot:dayHeadere and have fixed it to dayHeader. Still, does not work.
https://codepen.io/anon/pen/mgwjee?&editable=true&editors=111
<div id="app">
<v-app id="inspire">
<v-layout>
<v-flex>
<v-sheet height="400">
<!-- now is normally calculated by itself, but to keep the calendar in this date range to view events -->
<v-calendar
ref="calendar"
:now="today"
:value="today"
color="primary"
type="week"
>
<!-- the events at the top (all-day) -->
<template v-slot:dayHeader="{ date }">
<template v-for="event in eventsMap[date]">
<!-- all day events don't have time -->
<div
v-if="!event.time"
:key="event.title"
class="my-event"
#click="open(event)"
v-html="event.title"
></div>
</template>
</template>
<!-- the events at the bottom (timed) -->
<template v-slot:dayBody="{ date, timeToY, minutesToPixels }">
<template v-for="event in eventsMap[date]">
<!-- timed events -->
<div
v-if="event.time"
:key="event.title"
:style="{ top: timeToY(event.time) + 'px', height: minutesToPixels(event.duration) + 'px' }"
class="my-event with-time"
#click="open(event)"
v-html="event.title"
></div>
</template>
</template>
</v-calendar>
</v-sheet>
</v-flex>
</v-layout>
</v-app>
</div>
This snippet is saved directly from the vuejs website. (By the time I saved it, it doesn't work properly at least).
I expect the events to be displayed properly. If anyone has tried to use this weekly calendar and succeed please tell me on how do you fix it. I would be really appreciated!
Just replace v-slot by slot and slot-scope in your <template>:
Replace
<template v-slot:dayHeader="{ date }">
and
<template v-slot:dayBody="{ date, timeToY, minutesToPixels }">
by
<template slot="dayHeader" slot-scope="{ date }">
and
<template slot="dayBody" slot-scope="{ date, timeToY, minutesToPixels }">
here's a codepen working :
https://codepen.io/anon/pen/ErPZrK
I'm working on a project based on Dayspan Vuetify library (
https://github.com/ClickerMonkey/dayspan-vuetify ).
I don't know how i can add a button inside each day cell. Someone help will be welcome!
Live Demo
You can put whatever you want in the template (see the button):
https://github.com/ClickerMonkey/dayspan-vuetify-example/blob/master/src/App.vue
<template slot="eventTimeTitle" slot-scope="{calendarEvent, details}">
<div>
<v-icon class="ds-ev-icon"
v-if="details.icon"
size="14"
:style="{color: details.forecolor}">
{{ details.icon }}
</v-icon>
<v-btn outline #click="doSomething" color="indigo">Button</v-btn>
<strong class="ds-ev-title">{{ details.title }}</strong>
</div>
<div class="ds-ev-description">{{ getCalendarTime( calendarEvent ) }}</div>
</template>
Add a method for the click:
doSomething(e) {
console.log(e);
alert('clicked')
}