I am using Form Tags components bootstrap-vue framework. I want to use vue-simple-suggest component (from npm) with form tags to suggest words related to user's query. User can select multiple words from suggestion, and the selected word will be saved in form tags as a pill as shown in image below.
I don't know how to merge both the components as a single component (or more better way), so that I can use UI feature of bootstrap with auto-suggest feature of a third party module.
I am learning VueJs, I don't know what should I learn to do this?
Here is my code:
<template>
<div>
<vue-simple-suggest
v-model="chosen"
mode="select"
:list="simpleSuggestionsList"
:filter-by-query="true"
:destyled="false"
>
<b-form-tags
placeholder="Enter Keyword"
size="lg"
tag-variant="success"
tag-pills
remove-on-delete
separator=","
class="my-3"
@input="updateValue"
></b-form-tags>
</vue-simple-suggest>
</div>
</template>
<script>
import VueSimpleSuggest from 'vue-simple-suggest'
import 'vue-simple-suggest/dist/styles.css'
export default {
name: "SeedWordsSuggestions",
data() {
return {
chosen: '',
seedWords: []
}
},
components: {
VueSimpleSuggest
},
methods: {
simpleSuggestionsList() {
return [
'Angular',
'ReactJs',
'VueJs'
]
},
addSelectedWord(e) {
console.log(`addSelectedWord`, e)
},
updateValue(value) {
const pos = value.length
this.seedWords.push(value[pos - 1])
console.log(this.seedWords)
}
}
}
</script>
<style scoped>
</style>
The following solution hacks together the two components to create an editable combobox with tag-pills.
According to the caveat docs of vue-simple-suggest
, its custom input components must emit the input
, focus
and blur
events, as well as have a value
prop. In addition, there are a few undocumented events that are required from the component: click
, keydown
, and keyup
.
b-form-tags
has a value
prop, but is missing several of the required events. However, you could access its internal input
element to attach your own event handlers that forward-$emit
the events:
export default {
async mounted() {
// wait a couple ticks to ensure the inner contents
// of b-form-tags are fully rendered
await this.$nextTick()
await this.$nextTick()
// <b-form-tags ref="tags">
const input = this.$refs.tags.getInput()
const events = [
'focus',
'blur',
'input',
'click',
'keydown',
'keyup'
]
events.forEach(event =>
input.addEventListener(event, e => this.$refs.tags.$emit(event, e))
)
},
}
The changes above alone will cause the vue-simple-suggest
to properly appear/disappear when typing. However, it doesn't add/remove tags when interacting with the auto-suggestions. That behavior could be implemented by the following features:
Feature 1 implementation:
ref
s to the vue-simple-suggest
and b-form-tags
so that we could access the components in JavaScript later:<vue-simple-suggest ref="suggest">
<b-form-tags ref="tags" />
</vue-simple-suggest>
keydown
-handler on the inner input of b-form-tags
:export default {
mounted() {
//...
// <b-form-tags ref="tags">
const input = this.$refs.tags.getInput()
input.addEventListener('keydown', e => this.onKeyDown(e))
},
}
export default {
methods: {
async onKeyDown(e) {
if (e.key === 'Enter' || e.key === 'Tab') {
// prevent default so that the auto-suggestion isn't also
// added as plaintext in b-form-tags
e.preventDefault()
// <vue-simple-suggest ref="suggest">
if (this.$refs.suggest.hovered) {
this.$refs.tags.addTag(this.$refs.suggest.hovered)
} else {
const suggestions = await this.$refs.suggest.getSuggestions(e.target.value)
if (suggestions.length > 0) {
this.$refs.tags.addTag(suggestions[0])
} else {
// no match, so clear chosen
this.chosen = ''
}
}
}
}
}
}
b-form-tag
's automatic tag-adding upon ENTER by adding no-add-on-enter
prop:<b-form-tags no-add-on-enter />
Feature 2 implementation:
suggestion-click
-event handler:<vue-simple-suggest @suggestion-click="onSuggestionClick">
export default {
methods: {
onSuggestionClick(suggestion) {
this.$refs.tags.addTag(suggestion);
},
}
}
Feature 3 implementation:
remove-on-delete
prop to b-form-tags
:<b-form-tags remove-on-delete />
full demo
As an aside, you might be better off with Vuetify's v-combobox
, which supports the combination of the two components you're trying to merge, but I'll leave that to you to explore :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With