Vuetify is a popular UI framework for Vue apps.
In this article, we’ll look at how to work with the Vuetify framework.
Custom Filter on Autocomplete
We can add a custom filter with the v-autocomplete
component.
For example, we can write:
<template>
<v-container>
<v-row>
<v-col col="12">
<v-card class="overflow-hidden" color="purple lighten-1" dark>
<v-card-text>
<v-text-field color="white" label="Name"></v-text-field>
<v-autocomplete
:items="fruits"
:filter="customFilter"
color="white"
item-text="name"
label="Fruit"
></v-autocomplete>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="success" @click="save">Save</v-btn>
</v-card-actions>
<v-snackbar
v-model="hasSaved"
:timeout="2000"
absolute
bottom
left
>Your profile has been updated</v-snackbar>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
hasSaved: false,
model: null,
fruits: [
{ name: "apple", id: 1 },
{ name: "grape", id: 2 },
{ name: "orange", id: 3 },
],
};
},
methods: {
customFilter(item, queryText, itemText) {
const text = item.name.toLowerCase();
const searchText = queryText.toLowerCase();
return text.indexOf(searchText) > -1;
},
save() {
this.isEditing = !this.isEditing;
this.hasSaved = true;
},
},
};
</script>
We added the v-autocomplete
component with the items
prop.
The items
prop has the items for the autocomplete dropdown.
The filter
prop has the filter method that we want to do the filtering with.
Dense Autocomplete
We can add the dense
prop to reduce the autocomplete height and decrease the max height.
For instance, we can write:
<template>
<v-container>
<v-row>
<v-col col="12">
<v-card class="overflow-hidden" color="purple lighten-1" dark>
<v-card-text>
<v-autocomplete
dense
:items="fruits"
:filter="customFilter"
color="white"
item-text="name"
label="Fruit"
></v-autocomplete>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="success" @click="save">Save</v-btn>
</v-card-actions>
<v-snackbar
v-model="hasSaved"
:timeout="2000"
absolute
bottom
left
>Your profile has been updated</v-snackbar>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
hasSaved: false,
model: null,
fruits: [
{ name: "apple", id: 1 },
{ name: "grape", id: 2 },
{ name: "orange", id: 3 },
],
};
},
methods: {
customFilter(item, queryText, itemText) {
const text = item.name.toLowerCase();
const searchText = queryText.toLowerCase();
return text.indexOf(searchText) > -1;
},
save() {
this.isEditing = !this.isEditing;
this.hasSaved = true;
},
},
};
</script>
We just add the dense
prop to the v-autocomplete
to make it shorter.
Slots
We can change the output of the select with slots.
For example, we can write:
<template>
<v-container>
<v-row>
<v-col col="12">
<v-card color="blue-grey darken-1" dark :loading="isUpdating">
<v-form>
<v-container>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="name"
:disabled="isUpdating"
filled
color="blue-grey lighten-2"
label="Name"
></v-text-field>
</v-col>
<v-col cols="12">
<v-autocomplete
v-model="friends"
:disabled="isUpdating"
:items="people"
filled
chips
color="blue-grey lighten-2"
label="Select"
item-text="name"
item-value="name"
multiple
>
<template v-slot:selection="data">
<v-chip
v-bind="data.attrs"
:input-value="data.selected"
close
@click="data.select"
@click:close="remove(data.item)"
>
<v-avatar left>
<v-img :src="data.item.avatar"></v-img>
</v-avatar>
{{ data.item.name }}
</v-chip>
</template>
<template v-slot:item="data">
<template v-if="typeof data.item !== 'object'">
<v-list-item-content v-text="data.item"></v-list-item-content>
</template>
<template v-else>
<v-list-item-avatar>
<img :src="data.item.avatar" />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-html="data.item.name"></v-list-item-title>
<v-list-item-subtitle v-html="data.item.group"></v-list-item-subtitle>
</v-list-item-content>
</template>
</template>
</v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-form>
<v-divider></v-divider>
<v-card-actions>
<v-btn
:disabled="autoUpdate"
:loading="isUpdating"
color="blue-grey darken-3"
depressed
[@click](http://twitter.com/click "Twitter profile for @click")="isUpdating = true"
>
<v-icon left>mdi-update</v-icon>Update Now
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: "HelloWorld",
data() {
const src = "https://cdn.vuetifyjs.com/images/lists/1.jpg";
return {
autoUpdate: true,
friends: ["Sandra Adams", "Britta Holt"],
isUpdating: false,
name: "",
people: [
{ name: "Sandra Adams", avatar: src },
{ name: "Mary Smith", avatar: src },
{ name: "James Wong", avatar: src },
],
};
},
watch: {
isUpdating(val) {
if (val) {
setTimeout(() => (this.isUpdating = false), 3000);
}
},
},
methods: {
remove(item) {
const index = this.friends.indexOf(item.name);
if (index >= 0) this.friends.splice(index, 1);
},
},
};
</script>
We have the selection
slot to populate the name text and the avatar of the person entry.
The v-chip
component is a container for both of these items.
This code:
<template v-slot:selection="data">
<v-chip
v-bind="data.attrs"
:input-value="data.selected"
close
@click="data.select"
@click:close="remove(data.item)"
>
<v-avatar left>
<v-img :src="data.item.avatar"></v-img>
</v-avatar>
{{ data.item.name }}
</v-chip>
</template>
has the chip shown when we select an item.
Conclusion
We can add custom filtering and show custom content for autocompletes with Vuetify.