Show tooltip in Autocomplete dropdown items using Vuetify - javascript

I'm new to Vue.js and Vuetify
Problem - To show tooltip on each dropdown item in v-autocomplete
Solution - added v-tooltip component in item template
Code:
var app = new Vue({
el: "#app",
data: {
items: [{
value: 0,
text: "Matthews Webb"
},
{
value: 1,
text: "Teresa Ward"
},
{
value: 2,
text: "Cervantes Swanson"
},
{
value: 3,
text: "Helga Cooper"
},
{
value: 4,
text: "Solomon Jensen"
},
{
value: 5,
text: "Eliza Delgado"
},
{
value: 6,
text: "Dickson Parks"
},
{
value: 7,
text: "Etta Glenn"
},
{
value: 8,
text: "Alma Durham"
},
{
value: 9,
text: "Rosemary Conner"
}
],
selected: []
}
});
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.x/dist/vuetify.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-content>
<v-container>
<v-autocomplete :items="items" v-model="selected" clearable multiple>
<template v-slot:item="data">
<v-tooltip right>
<template slot="activator" slot-scope="{ on }">
<v-list-tile-action>
<v-checkbox v-model="selected" :value="data.item.value"></v-checkbox>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title v-html="data.item.text" v-on="on"></v-list-tile-title>
</v-list-tile-content>
</template>
<span>{{ data.item.text }}</span>
</v-tooltip>
</template>
</v-autocomplete>
</v-container>
</v-content>
</v-app>
</div>
Problems after implementing the solutions:
Checkboxes are not clickable or item cannot be selected if clicked on the checkbox
On searching the item some of the checkboxes shows selected
Vue Version - 2.6.12
Vuetify Version - 1.5.24
Is there any other way to show tooltip on autocomplete dropdown items without disturbing the functionality or is there any mistake in my solution

Solution:
The v-input--selection-controls__ripple Div overlaps the input box of the selection control; hence binds to the click instead.
To fix this I applied a simple CSS Hack. Conceptually position it above by using position and z-index:-10 for the div.
that is illustrated with edits marked below as /* <--------------- */
<div class="v-input__slot">
<div class="v-input--selection-controls__input">
<input aria-checked="false" role="checkbox" type="checkbox" value="1" style="
position: relative; /* <--------------- */
">
<div class="v-input--selection-controls__ripple" style="
position: absolute; z-index: -10; /* <--------------- */
"></div>
<i aria-hidden="true" class="v-icon material-icons theme--light">check_box_outline_blank</i>
</div>
</div>

Related

Change checkbox icon when checked Vuejs Vuetify

So I am trying to check the checkbox Icon to something more custom, perhaps a different icon, however, I tried a couple different things like pseudo elements with no success. right now what this does is loops through data and displays the name and when checked highlights it based on the css class. What I am trying to do is when check change the checkbox icon.
css
.unchecked{
color: gray;
}
.checked{
background-color: #ffff00;
}
Vuejs Component.
Vue.component('check-list', {
template: `
<v-container>
<v-row >
<v-col >
<v-checkbox
v-for="item in values"
:key="item.id"
:value="item.id"
v-model="selected"
>
<template v-slot:label>
<div :class="selected.includes(item.id) ? 'checked' : 'unchecked'">
{{item.name}}
</div>
</template>
</v-checkbox>
</v-col>
</v-row>
<pre>{{selected}}</pre>
</v-container>
`,
data: function () {
return {
selected: [],
values: [
{id:'1',name:'Name 1'},
{id:'2', name:'Name 2'},
{id:'3', name:'Name 3'},
],
ex4: ['red']
}
},
methods: {
},
})
new Vue({
el: '#components-demo',
vuetify: new Vuetify({
icons: {
iconfont: 'md',
},
}),
data: () => ({
}),
})
#chewie, it is possible to change the checkbox icon in Vuetify, There is a specia prop to handle this
:on-icon="'icon-name'"
:off-icon="'icon-name'"
Please find the full code below
<div id="app">
<v-app id="inspire">
<v-container
class="px-0"
fluid
>
<v-row >
<v-col >
<v-checkbox
:on-icon="'mdi-heart'"
:off-icon="'mdi-home'"
v-for="item in values"
:key="item.id"
:value="item.id"
v-model="selected"
>
<template v-slot:label>
<div :class="selected.includes(item.id) ? 'checked' : 'unchecked'">
{{item.name}}
</div>
</template>
</v-checkbox>
</v-col>
</v-row>
<pre>{{selected}}</pre>
</v-container>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
selected: [],
values: [
{id:'1',name:'Name 1'},
{id:'2', name:'Name 2'},
{id:'3', name:'Name 3'},
],
ex4: ['red']
}
},
})
Please find the working codepen here:
https://codepen.io/chansv/pen/QWdEPvB?editors=1010

How to have the button span the whole width?

I am using Vuetify card with a layout and rendering some dynamic vuetify components inside of the card on checkbox selection which renders either a divider, a spacer, toolbar or button but i am not able to figure out how can i make the buttons span the entire width?
Basically the dynamic button should look like the button at the end rendering the entire width.
Please check this codepen.
Please check this working example:-
new Vue({
el: "#app",
data() {
return {
pricing: [{
text: "Actual price:",
value: "$17,000",
},
{
text: " Discount",
value: "$12,345",
}
],
elements: [{
title: "Divider",
value: "v-divider"
},
{
title: "Toolbar",
value: "v-toolbar"
},
{
title: "Button",
value: "v-btn"
}
],
selected: []
};
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<link rel="stylesheet" href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout row>
<v-flex xs6>
<v-card>
<v-card-text>
<v-layout row justify-space-between v-for="option in pricing" :key="option.value" class="my-3">
<span :class="option.class">{{option.text}}</span>
<component v-for="(el, i) in selected" :key="i" :is="el.value"></component>
<span>{{option.value}}</span>
</v-layout>
<v-layout row justify-center>
<v-flex xs11>
<v-btn block>
Request
</v-btn>
</v-flex>
</v-layout>
</v-card-text>
</v-card>
<v-flex v-for="el in elements" :key="el.value">
<v-checkbox :value="el" v-model="selected" :label="el.title">
</v-checkbox>
</v-flex>
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
Any help will be appreciated. Thank you so much.
Use .flex.xs12 (12 = flex-basis: 100%;)
-or-
remove xs12 (And add button block attribute = flex: 1 0 auto;).
<!-- block buttons extend the full available width -->
<template>
<v-btn block>
Block Button
</v-btn>
</template>
https://vuetifyjs.com/en/components/buttons/#block

How to render dynamic elements in VueJS?

I am trying to create an app where users can select what kind of vuetify element they would like to render on the page? So I have 4 options that users can select from. I want to render the respective vuetify component on click, so if the user selects divider a <v-divider> </v-divider> should render, for a spacer, a <v-spacer></v-spacer> and for a toolbar a <v-toolbar></v-toolbar> and if they select text then a <v-btn></v-btn> with text would be displayed. I am really stuck on how I can do it.
This is a sample codepen
new Vue({
el: "#app",
data() {
return {
elements: [{
title: "Divider",
value: "divider"
},
{
title: "Spacer",
value: "spacer"
},
{
title: "Toolbar",
value: "toolbar"
},
{
title: "Text",
value: "text"
}
],
selected: []
};
},
methods: {
renderElements() {
console.log(this.selected);
this.selected = [];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout column>
<v-flex v-for="el in elements" :key="el.value">
<v-checkbox :value="el.value" v-model="selected" :label="el.title"></v-checkbox>
</v-flex>
<v-btn #click="renderElements"> Render Dynamic Elements</v-btn>
</v-layout>
</v-container>
</v-app>
</div>
I would really appreciate some help with this.
It seems you need to use dynamic components:
<component v-for="(el, i) in selected" :key="i" :is="el.value"></component>
new Vue({
el: "#app",
data() {
return {
elements: [
{
title: "Divider",
value: "v-divider"
},
{
title: "Spacer",
value: "v-spacer"
},
{
title: "Toolbar",
value: "v-toolbar"
},
{
title: "Text",
value: "v-btn"
}
],
selected: []
};
},
methods: {
renderElements() {
console.log(this.selected);
this.selected = [];
}
}
});
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout column>
<v-flex v-for="el in elements" :key="el.value">
<v-checkbox :value="el" v-model="selected" :label="el.title">
</v-checkbox>
</v-flex>
<v-btn #click="renderElements"> Render Dynamic Elements</v-btn>
<component v-for="(el, i) in selected" :key="i" :is="el.value"></component>
</v-layout>
</v-container>
</v-app>
</div>
new Vue({
el: "#app",
data() {
return {
elements: [
{
title: "Divider",
value: "v-divider",
show: false
},
{
title: "Spacer",
value: "v-spacer",
show: false
},
{
title: "Toolbar",
value: "v-toolbar",
show: false
},
{
title: "Text",
value: "v-btn",
show: false
}
],
selected: []
};
},
methods: {
renderElements() {
console.log(this.selected);
for(let i=0; i<this.elements.length; i++)
{
this.elements[i].show = this.selected.includes(i);
}
}
}
});
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container>
<v-layout column>
<v-checkbox v-for="(item, i) in elements"
:key="i"
:label="item.title"
:value="i"
v-model="selected"
></v-checkbox>
<v-btn #click="renderElements"> Render Dynamic Elements</v-btn>
<component v-for="(item, i) in elements" :key="i + 10" :is="item.value" v-if="item.show">{{ item.title }}</component>
</v-layout>
</v-container>
</v-app>
</div>

Vuetify combobox add option multiple times?

I am using the vuetify framework and I am running into this issue where I am not sure how I can add an item from the list multiple times. I have a dropdown list and I would like to add the option foo or any option multiple times on select. Here is a link to the demo codepen.
So right now if I select foo or any other option and then select it again from the dropdown list, it goes away, instead I want another chip with same option
added into it?
new Vue({
el: '#app',
data() {
return {
items: [{
text: 'Foo',
value: 'foo'
},
{
text: 'Bar',
value: 'bar'
},
{
text: 'biz',
value: 'buzz'
},
{
text: 'buzz',
value: 'buzz'
}
],
}
}
})
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<v-app id="inspire">
<v-container>
<v-combobox :items="items" label="Add Multiple Chips" multiple small-chips solo deletable-chips>
<template v-slot:item="{ index, item }">
<v-list-tile-content>
{{item.text}}
</v-list-tile-content>
</template>
<template v-slot:selection="{ index, item }">
<v-chip close dark color="info">
{{ item.text }}
</v-chip>
</template>
</v-combobox>
</v-container>
</v-app>
</div>
If anyone has any clue on how to achieve this. It will be much appreciated. Thank you
A couple of small adjustments,
put a .stop on the item click to prevent Vuetify from processing after your handler
tell the combo-box to use arr for :value
add a delete click handler to v-chip and corresponding method (NB this works on Vuetify 2.1.0, but not on Vuetify 1.5.14 as used on the Codepen. If you don't need that specific version, install the latest.
Codepen Vuetify v1.5.14
CodeSandbox Vuetify v2.1.0
<template>
<div id="app">
<v-app id="inspire">
<v-container>
<v-combobox
:items="items"
label="Add Multiple Chips"
multiple
small-chips
solo
deletable-chips
:value="arr"
>
<template v-slot:item="{ index, item }">
<v-list-tile-content #click.stop="multipleSelection(item)">{{item.text}}</v-list-tile-content>
</template>
<template v-slot:selection="{ index, item }">
<v-chip close dark color="info"
#click:close="deleteChip(item)" >{{ item.text }}</v-chip>
</template>
</v-combobox>
</v-container>
</v-app>
</div>
</template>
<script>
export default {
name: "playground",
data: () => ({
arr: [],
items: [
{
text: "Foo",
value: "foo"
},
{
text: "Bar",
value: "bar"
},
{
text: "biz",
value: "buzz"
},
{
text: "buzz",
value: "buzz"
}
]
}),
methods: {
multipleSelection(item) {
this.arr.push({...item});
console.log(this.arr);
},
deleteChip(item) {
this.arr = this.arr.filter(x => x !== item);
console.log(this.arr);
}
}
};
</script>
Addressing the problem of long selection lists being obscured by the dropdown menu,
The dropdown menu looks like this at runtime (via chrome developer tools)
<div class="v-menu__content theme--light menuable__content__active v-autocomplete__content"
style="max-height: 304px; min-width: 357px; top: 149px; left: 12px; transform-origin: left top; z-index: 8;">
<div role="listbox" tabindex="-1" class="v-list v-select-list v-sheet v-sheet--tile theme--light theme--light"
id="list-261">
<div tabindex="0" role="menuitem" id="list-item-267" class="v-list-item v-list-item--link theme--light">Foo</div>
<div tabindex="0" role="menuitem" id="list-item-268" class="v-list-item v-list-item--link theme--light">Bar</div>
<div tabindex="0" role="menuitem" id="list-item-269" class="v-list-item v-list-item--link theme--light">biz</div>
</div>
</div>
and has these styles
element.style {
max-height: 304px;
min-width: 357px;
top: 149px;
left: 12px;
transform-origin: left top;
z-index: 8;
}
Vuetify changes the top: 149px in it's selection handler, but since we turned that off we need to call updateMenuDimensions() in our own handler multipleSelection().
To do this, add a ref to the combobox,
<v-combobox
:items="items"
label="Add Multiple Chips"
multiple
small-chips
solo
deletable-chips
:value="arr"
ref="combobox"
>
...
</v-combobox>
Then add the call to updateMenuDimensions, inside a nextTick() to allow the selection box to settle.
methods: {
multipleSelection(item) {
this.arr.push({ ...item });
console.log(this.arr);
this.$nextTick(() => this.$refs.combobox.updateMenuDimensions())
},
deleteChip(item) {
this.arr = this.arr.filter(x => x !== item);
console.log(this.arr);
this.$nextTick(() => this.$refs.combobox.updateMenuDimensions())
}
}
Codepen Vuetify v1.5.14 (NB not deleting chips).
Preventing text from adding an item
There's another problem (for anyone following here but not seeing the chat room discussion). I've separated the answers for each issue, to make things easier to follow.
Feel free to vote on all answers :).
Problem
If the user types into the combobox, the expectation is that the list will be filtered, and it is.
But if the user presses enter after the text, an item is added and this is not desired.
We tried a permutations of event suppression, including,
#keydown.enter.prevent
#keypress.enter.prevent
#submit.prevent
#keydown.enter.prevent="enterItem" with event.preventDefault() in the handler
#blur.prevent
plus permutations with .stop, .capture.
None of the event suppression worked, so a hacky way to do it is to v-if the v-chip
<v-combobox
...various attributes as before
>
<template v-slot:item="{ index, item }">
...
</template>
<template v-slot:selection="{ index, item }">
<v-chip v-if="item.text" ...other attributes >{{ item.text }}</v-chip>
</template>
</v-combobox>
This works because the added item has no text (reason unknown), and the variable this.arr does not get modified when pressing the enter key as described.
Codepen

Vue updates all button text after changing specific button

Hi everyone I'm playing around with Vue JS but for some how I cannot get what I expected. Below are my code.
Template
<div id="app">
<v-app id="inspire">
<div class="text-xs-center" v-for="x in count" :key="x">
<v-menu offset-y>
<v-btn
slot="activator"
color="primary"
dark
>
{{name}}
</v-btn>
<v-list>
<v-list-tile
v-for="(item, index) in items"
:key="index"
#click="test(item.title)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</div>
</v-app>
</div>
Vue
new Vue({
el: '#app',
data: () => ({
name: 'default',
items: [
{ title: 'Click Me 1' },
{ title: 'Click Me 2' },
{ title: 'Click Me 3' },
{ title: 'Click Me 2' }
],
count: 10
}),
methods: {
test(title) {
this.name = title
}
}
})
What I want is that when I change a specific button text the other buttons should not be affected. But it seems my code is doing the opposite. What am I missing here? Any help, explanation would be much appreciated. Thanks
new Vue({
el: '#app',
data: () => ({
name: 'default',
items: [
{ title: 'Click Me 1' },
{ title: 'Click Me 2' },
{ title: 'Click Me 3' },
{ title: 'Click Me 2' }
],
count: 10
}),
methods: {
test(title) {
this.name = title
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.3/dist/vuetify.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.3/dist/vuetify.min.css">
<div id="app">
<v-app id="inspire">
<div class="text-xs-center" v-for="x in count" :key="x">
<v-menu offset-y>
<v-btn
slot="activator"
color="primary"
dark
>
{{name}}
</v-btn>
<v-list>
<v-list-tile
v-for="(item, index) in items"
:key="index"
#click="test(item.title)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</div>
</v-app>
</div>
You are iterating over a normal number, in your example 10, so you are just showing 10 times the same variable name.
If you now change that variable name to something, it will change in all the buttons accordingly.
You need some way to save the different names, e.g. an array of objects like your items with all the titles.
I took your code and changed it a bit. Instead of iterating over a fixed count, I created an array of names and iterate over that array. When you click one of the buttons and change the text, instead of just changing the universal name attribute - you change the name at the position in the array.
new Vue({
el: '#app',
data: () => ({
names: [
{name: 'default 1'}, {name: 'default 2'}, {name: 'default 3'}, {name: 'default 4'}],
items: [
{ title: 'Click Me 1' },
{ title: 'Click Me 2' },
{ title: 'Click Me 3' },
{ title: 'Click Me 4' }
],
}),
methods: {
test(title, index) {
this.names[index].name = title
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.5.3/vuetify.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.5.3/vuetify.css.map">
<div id="app">
<v-app id="inspire">
<div class="text-xs-center" v-for="(x, index) in names" :key="'name' + index">
<v-menu offset-y>
<v-btn
slot="activator"
color="primary"
dark
>
{{x.name}}
</v-btn>
<v-list>
<v-list-tile
v-for="(item, i) in items"
:key="'item' + i"
#click="test(item.title, index)"
>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
</div>
</v-app>
</div>

Categories

Resources