I'm trying to create a dropdown menu with a list I have populated from the backend. Here's the library in question Vue Treeselect
Once the user tries to enter something that's not inside, I want to be able to dynamically add it, and later when the request gets submited, create that value on the backend. However, the library doesn't seem to provide a way to override the default behaviour. Here's what I tried so far.
https://codesandbox.io/s/musing-sutherland-i5e8f?fontsize=14&hidenavigation=1&theme=dark
<template>
<div id="app">
<div class="container mt-4 mx-auto">
<treeselect
@search-change="handleSearch"
:multiple="true"
:options="options"
placeholder="Select your favourite(s)..."
no-results-text="No results found... Press enter to add"
v-model="value"
>
</treeselect>
<pre class="bg-gray-200 text-gray-600 rounded mt-4 p-4">{{
JSON.stringify(value, null, 2)
}}</pre>
<h5>Search text: {{ text }}</h5>
<button
@click="appendNewItem"
class="focus:outline-none text-white text-sm py-2.5 px-5 rounded-md bg-blue-500 hover:bg-blue-600 hover:shadow-lg"
>
Add
</button>
</div>
</div>
</template>
<script>
// import the component
import Treeselect from "@riophae/vue-treeselect";
// import the styles
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
name: "App",
components: {
Treeselect,
},
data() {
return {
lastId: 0,
text: "",
value: [],
options: [
{ id: 1, label: "Option #1" },
{ id: 2, label: "Option #2" },
],
};
},
methods: {
handleSearch(ev) {
this.text = ev;
},
makeId() {
return `new-item-${++this.lastId}`;
},
appendNewItem() {
this.options = [...this.options, { id: this.makeId(), label: this.text }];
},
},
};
</script>
Even my button solution doesn't work, because as soon as you leave the area of the tree-select input, the text gets reset to an empty string, so pressing the button adds an empty text.
Given the current documentation of Vue-Treeselect how can I make it call my appendNewItem() function when the user presses enter and the treeselect has no results?
Ideally, I would like to do something like this:
<treeselect (other-props)>
<template #no-results={ node }>
<span>No results found for {{ node.text }}</span>
<button @click="appendNewItem">Add {{ node.text }}</button>
</template>
</treeselect>
But, unfortunately this is not supported by the library API. And it still doesn't solve the question of "creating a new field when enter key is pressed" but it would be a nice start regardless.
Have to say, this is a tough one.
The library doesn't provide a way to enable the functionality you've described but what you can do is use some low-level Vue APIs to override the library methods and try to achieve the effect you need.
Essentially, we're gonna override the
select(node)function from the library in an attempt to make it bend to our needs.Then, remember to use the overridden component in your code:
This IS a working solution, however, I would have to recommend using this code with caution, as it creates dependencies with internal implementation with the library! That means if you update the library from
package.jsonyou're introducing a breaking change to your project even in case of minor version updates! Because this code relies even on "private" functions from the library, and not just the public-facing API. You could try to future-proof it, but it might be smarter to just opt-in and use some different library that does provide your needs.Here is a Codesandbox that demonstrates this: Link