It would be good if there was an implementation of autocomplete with a limited group of options, a kind of q-select with autocomplete.
Is there a way to do this already?
What do you mean "limited group of options"? You specify autocomplete options yourself. Also, q-select has filter option, take a look at it.
Hi,
Not sure what you mean. You can currently:
Am I missing something?
I believe he means QSelect with filter option, but fetching options asynchronously... is it possible in any way? I'm kinda needing this too...
Example:
I have this "Client" field and i want to fetch them by their name, but i need to set it's value in the field... using autocomplete, after i select the option i want, instead showing (Client A, Client B), it will show their id (1, 2)...
If we get data like this from the server:
"sellers": [
{
"id": "e1e7519f-fe04-4cf8-96d9-fbbbccefe52f",
"name": "Indonesia Test Seller"
},
{
"id": "b8c240e7-6afe-4274-93ec-7d833657fe5b",
"name": "Taiwan Test Seller 1"
},
{
"id": "98bfa6a5-5558-4d21-9c6c-db5d6267acc4",
"name": "Taiwan Test Seller 2"
}
]
and if there are thousands Sellers, then how do we search them partially?
Let's say: fetch data by search term + limit by 10.
If I'm using QAutocomplete, I can do server-side filter, e.g. by seller's name.
But I don't know how to keep the seller's id in the client-side.
If I'm using QSelect, I can only do client-side filter.
Should I use QSearch separately to do server-side filter?
That's a workaround I am using while this function is not supported out of the box...
1) Create a new component (mb-auto-complete) using QChipsInput and QAutocomplete:
<template>
<div>
<q-chips-input v-model="chipList"
:float-label="floatLabel"
:disable="disable"
@remove="remove"
@duplicate="duplicate"
@input="input">
<q-autocomplete value-field="label"
:min-characters="3"
:max-results="30"
@search="handleSearch"
@selected="selected" />
</q-chips-input>
</div>
</template>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
<script>
import { QChipsInput, QAutocomplete } from 'quasar'
import _ from 'lodash'
export default {
components: {
QChipsInput,
QAutocomplete
},
props: {
apiUrl: String,
floatLabel: String,
disable: Boolean,
selectedList: {}
},
data: function () {
return {
chipList: [],
isDuplicated: false,
isArray: false,
selectedListTemp: []
}
},
watch: {
selectedList: function () {
// on change update chips (needed in case the initial kvp is comming from some api)
this.selectedListTemp = _.cloneDeep(this.selectedList)
this.updateChips()
}
},
created () {
this.selectedListTemp = _.cloneDeep(this.selectedList)
if (Array.isArray(this.selectedList)) this.isArray = true
else this.isArray = false
this.updateChips()
},
methods: {
selected (item, keyboard) {
// Insert kvp
if (!keyboard && !this.isDuplicated) {
if (this.isArray) this.selectedListTemp.push(item)
else this.selectedListTemp = item
this.updateChips()
this.$emit('update:selectedList', this.selectedListTemp)
}
this.isDuplicated = false
},
duplicate (label) {
// flag chip already exist
this.isDuplicated = true
},
remove (e) {
// also remove kvp
if (this.isArray) this.selectedListTemp.splice(e.index, 1)
else this.selectedListTemp = {}
this.$emit('update:selectedList', this.selectedListTemp)
},
input (e) {
// remove chip after enter. The chips are inserted on updateChips method (that's for not accept chips that does not exist in filter)
if (this.isArray) this.chipList.splice(this.selectedListTemp.length, 1)
else this.selectedListTemp = {}
this.updateChips()
},
handleSearch (term, done) {
this.$axios
.get(this.apiUrl + '/' + term)
.then(response => {
done(response.data)
})
.catch(() => {
done([])
})
},
updateChips () {
this.chipList = []
if (this.isArray) {
for (let i = 0, size = this.selectedListTemp.length; i < size; i++) {
this.chipList.push(this.selectedListTemp[i].label)
}
} else if (this.selectedListTemp.label) this.chipList.push(this.selectedListTemp.label)
}
}
}
</script>
2) Call the new component passing the api url and the result variable, here 'client'.
Note 1) 'client' can either be an object or an array. If it is declared as an object the user will be able to select only one chip. If it's an array the user can select as many chips he wants.
Note 2) The API returns an array of type: [ {value: 1, label: 'Client A'}, {value: 2, label: 'Client B'}, ... ]
Note 3) The component adds /blabla to the API call, where "blabla" is the text entered by the user in the autocomplete. So my backend API is using "blabla" to filter the results.
<template>
<div>
<mb-auto-complete apiUrl="client/kvp"
floatLabel="Client name"
:selectedList.sync="client"
:disable="false" />
</div>
</template>
<script>
import mbAutoComplete from './../../components/mbAutoComplete'
export default {
components: {
mbAutoComplete
},
data: function () {
return {
client: {value: 164, label: 'Client 1'}
// client: [{value: 164, label: 'Client 1'}]
}
}
}
</script>
Well then, QAutocomplete is the best thing I can use.
If we get data like this from the server:
"sellers": [ { "id": "e1e7519f-fe04-4cf8-96d9-fbbbccefe52f", "name": "Indonesia Test Seller" }, { "id": "b8c240e7-6afe-4274-93ec-7d833657fe5b", "name": "Taiwan Test Seller 1" }, { "id": "98bfa6a5-5558-4d21-9c6c-db5d6267acc4", "name": "Taiwan Test Seller 2" } ]and if there are thousands Sellers, then how do we search them partially?
Let's say: fetch data by search term + limit by 10.* "Limit by 10" can be a constant. * But "search term" should be a user input.If I'm using QAutocomplete, I can do server-side filter, e.g. by seller's name.
But I don't know how to keep the seller's id in the client-side.If I'm using QSelect, I can only do client-side filter.
Should I use QSearch separately to do server-side filter?
@yaliv i am searching for the same solution. q-select with server side data feteched asynchronously.
q-autocomplete does the thing but it is not possible to bind it to q-select.
Have you found a solution for this?
@NicoP-S
I practically don't use QSelect at all. I just keep the seller's id manually (or array of them for multi-select). For example, I created this component: SearchableMultiselect.vue.zip. For the server-side filtering, I just forward the search event to the parent component, so I can do anything there. The most important thing is the done function should be called with an array of objects containing id and value keys.
Usage:
<SearchableMultiselect
ref="recipients"
v-model="form.recipients"
:debounce="1000"
:min-characters="2"
:max-results="10"
color="info"
chips-bg-color="brown-5"
@search="findSellers"
/>
async findSellers(terms, done) {
const queryResult = await this.$apollo.query({
client: 'product',
query: FIND_SELLERS,
variables: {
search: terms
}
})
const sellers = queryResult.data.allSellers.sellers.map(seller => ({
value: seller.name,
label: seller.name,
sublabel: seller.city + ', ' + seller.country,
id: seller.id
}))
done(sellers)
}
Most helpful comment
If we get data like this from the server:
and if there are thousands Sellers, then how do we search them partially?
Let's say: fetch data by search term + limit by 10.
If I'm using QAutocomplete, I can do server-side filter, e.g. by seller's name.
But I don't know how to keep the seller's id in the client-side.
If I'm using QSelect, I can only do client-side filter.
Should I use QSearch separately to do server-side filter?