Vuetify - combobox badges with a removable button - vue.js

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
/>

Related

Is it possible to create a grid layout in a list?

disclaimer: I'm just learning vue.js and vuetify and I'm not very familiar with javascript. I'm writing my first vue.js app.
I'm using vue 2.x and vuetify 2.x.
I need to create a scrolable list of items on which the user will be able to perform actions. For now, I'm just concerned about the layout of the list items.
The item is made of two visible information, a number and a text (like an inventory) that should be displayed in two columns. The numbers should be right aligned in their column and the text left aligned.
This is what I have so far.
<template>
<v-list dense>
<template v-for="(item, index) in items">
<v-list-item :key="item.r">
<v-list-item-content class="font-weight-bold">
<v-list-item-title>
{{ item.n }} {{ item.t }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
<v-divider :key="index"></v-divider>
</template>
</v-list>
</template>
<script>
export default {
name: "itemList",
data() {
return {
items: this.$store.state.currentItems,
};
},
};
</script>
Is it possible to use a layout inside a list item ? If not, how could I create the desired column alignment ?
In case it could influence the implementation, the actions are
make the item a sliding button with multiple selectable actions
or make the number and the text individual clickable flat buttons with popup menus
manually reorder list items with drag and drop.
An alternative to the sliding button (if not possible) is to make the number and text flat buttons with a popup menu. I guess this could influence how to define the layout.
generally with the use of v-row and v-col you can implement a layout and this is true inside of a v-list-item-content, for example check the code below (I'm not sure if I understood the layout you've asked for correctly or not but it must give you a hint)
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
items: [{
t: 'title one',
n: 1
},
{
t: 'title two',
n: 2
},
{
t: 'title three',
n: 3
},
{
t: 'title four',
n: 4
},
],
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app>
<v-main>
<v-container>
<v-list dense>
<template v-for="(item, index) in items">
<v-list-item :key="item.n">
<v-list-item-content class="font-weight-bold">
<v-row>
<v-col cols="6">
<v-row no-gutters justify="end">{{ item.n }}</v-row>
</v-col>
<v-col cols="6">
<v-row no-gutters>{{ item.t }}</v-row>
</v-col>
</v-row>
</v-list-item-content>
</v-list-item>
<v-divider :key="`divider-${item.n}`"></v-divider>
</template>
</v-list>
</v-container>
</v-main>
</v-app>
</div>

Hide tab headers in vuetify

I'm using #nuxtjs/vuetify with nuxt.js as combo.
I'm using the component v-tabs with v-tabs-items in my page used as grouped settings.
What i want to achieve is simple but i couldn't find the solution.
if there is just one group of settings. i don't want to show the tab header.
if there are multiple groups of settings. then the tab headers may show.
so what the code is now:
<v-tabs v-model="tab"> <!-- GROUPED SETTINGS ORDERED IN TABS -->
<v-tab class="mx-4" v-for="(tab, index) in Object.keys(content_fields)" :key="index">{{ tab }}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item>
<!-- item -->
</v-tab-item>
</v-tabs-items>
i tried to do a v-if on the v-tabs. so if there is just one group the v-tabs will not show.
but then the v-tabs-items will not show at all. even if i set the tab property on the good tab.
is there any solution that will give the result that i want?
I did with v-show:
HTML:
<div id="app">
<v-app id="inspire">
<v-tabs>
<v-tab v-show="tabs.length > 1" v-for="i in tabs" :key="i.name" :href="`#tab-${i.name}`"> {{ i.text }} </v-tab>
<v-tab-item v-for="i in tabs" :key="i.name" :value="'tab-' + i.name">
<v-card flat tile>
<v-card-text>{{ i.text }}</v-card-text>
</v-card>
</v-tab-item>
</v-tabs>
</v-app>
</div>
JS:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
tabs: [
{ name: 1, text: 'One' },
//{ name: 2, text: 'Two' }
]
}
}
})
Here you can see the live demo: https://codepen.io/ljcordero/pen/wvBXqWv
Hope this help.

how to pass text, button and icon to v-radio 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>

Vuetify: show tooltip with a condition

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>

Vuetify append item to select menu not selecting as normal item

I have a simple select menu using Vuetify (Vue 2.0) seen in fiddle here:
https://jsfiddle.net/2ku5a6f4/
The option is added, but the menu does not close and select like the other options and the menu stays open
My reference is from the Vuetify docs: https://vuetifyjs.com/en/components/selects
under 'prepend/append item slots
<div id="app">
<v-app dark>
<v-select
:items="items"
clearable
v-model='selectedItem'
label="...will 'four' close menu?"
>
<template v-slot:append-item>
<v-divider class="mb-2"></v-divider>
<v-list-tile >
<v-list-tile-content>
four
</v-list-tile-content>
</v-list-tile>
</template>
</v-select>
</v-app>
</div>
var vm = new Vue({
el: "#app",
data: {
items: ["one", "two", "three"],
selectedItem: ''
}
});
I received an answer from Vuetify devs:
I needed to add:
:menu-props="{closeOnContentClick: true}"
<v-select
:items="items"
clearable
v-model='selectedItem'
:menu-props="{closeOnContentClick: true}"
label="...will 'four' close menu?">
You are using version v0.14.8, not even v0.15 supports wanted slots. Consider update.
https://v1.vuetifyjs.com/releases/0.15/#/components/selects