I'm using https://vue-multiselect.js.org in my Vue component. I am using AJAX to update the select list option, and I see in the inspector that there are 10 values.
But when I actually click into the multiselect list, I only see a subset of these items and I can't figure out why.... Here are my multi-select props/events:
<multiselect
v-model="organization"
:allow-empty="true"
:loading="loading"
:options="organizationSearch"
:preserve-search="true"
#search-change="searchOrganizations"
#select="organizationSelected"
#remove="organizationDeselected"
placeholder="Search Organizations"
label="name"
track-by="id"
class="multiselect my-3"
>
</multiselect>
I figured it out. I dug into the component code a bit and found that all the options WERE in the options prop, but there were only 3 in the filteredOptions computed field. I added
:internal-search="false" into my component and then this fixed it.
I think the ultimate issue here had to do with conflict between the internal filtering, and the dynamic update of the options I was doing via AJAX.
Below is the definition of filteredOptions in the actual component definition.
It could be more helpful if you expand the options array in the inspector, so we could see what properties are presented in the objects.
track-by is used to identify the option within the options list thus it’s value has to be unique.
You set track-by="id" and label="name", so your options array should look something like this:
options: [
{ id: 1, name: 'Option #1' },
{ id: 2, name: 'Option #2' },
{ id: 3, name: 'Option #3' },
],
Make sure that all the items in your options array have an id property and it is unique for all of them, because the items with the same id will not appear in the multiselect list.
This depends on the structure of your options.
It shows that they are objects when they should probably be literal values.
Related
I am obtaining from an API the data to fill a v-select type component, the component is filled correctly and I also obtain the options that the user already had assigned (multiple)
And the v-select component are filled correctly
But when i try to add another option occurs the next
Here is the Source Code
<validation-provider
#default="validationContext"
name="skill"
>
<b-form-group
label="Skills"
label-for="skill_id"
:state="getValidationState(validationContext)"
>
<v-select
v-model="itemData.skills"
:dir="$store.state.appConfig.isRTL ? 'rtl' : 'ltr'"
multiple
:options="skillOptions"
:clearable="false"
:reduce="(val) => val.value"
input-id="skill_id"
/>
<b-form-invalid-feedback
:state="getValidationState(validationContext)"
>
{{ validationContext.errors[0] }}
</b-form-invalid-feedback>
</b-form-group>
</validation-provider>
Here i have the array of objects, with multiple elements
itemEdit.value.skills
Then map to get a reduced array with only the value and label
I have probed using only the label without value and the result is the same
const openEdit = item => {
isSidebarActive.value = true
itemEdit.value = item
itemEdit.value.skills = item.skills.map(skill => ({
value: skill.id,
label: skill.skill,
}))
isAdd.value = false
}
Everything apparently goes right, the v-model match correctly with the available options, the problem comes when the user interact with the vSelect to add another item, the already selected items disappear
Thanks in advance
Based on this page o the Vue Select Documentation, the reduce prop is usually meant for use with a label prop, and is only needed if you provide an object to v-select.
I suspect you are providing an array of primitives in your v-model (ie itemData.skills is an array of strings) instead of an array of objects. If it is an array of objects instead, then I suspect you either don't have a [label] key on the object (the default that label is set to), or you don't have a [value] key (what you are trying to return with your reduce prop).
Ideally, you would give us an example of your data coming in for us to be able to help you better.
thanks for listen, the problem was solved removing:
:reduce="(val) => val.value"
From
<v-select
v-model="itemData.skills"
:dir="$store.state.appConfig.isRTL ? 'rtl' : 'ltr'"
multiple
:options="skillOptions"
:clearable="false"
:reduce="(val) => val.value"
input-id="skill_id"
/>
My issue is simple but kinda tricky.
I'm inside a v-for, named filter, and I'd like to display thing like item.properties.*value* which is the :items I passed to vuetify autocomplete , and the value has to different in each loop, because the infos to desired are not the same. In other words, I'd like to filter displayed items depending on the object I am.
Notice that the properties is an object with multiples props and I want to display only 1 on the prop in every loop. I did not made any v-forfor this object containing multiples props
The name of the prop I want to show as list on my autocomplete is determined by a variable called "label" that I passed as props in my v-for and therefore, in my looped component which looks like this label : 'filters.mission' (for example, mission)
(I have a traduction file so that's the reason we have a 'filters.mission' here because its all translated, for all the props)
Here is a simple exemple :
// imported array from data I want to display, binded as :items="data"
[
//..stuff
properties : {
"mission": foo,
"driver": bar,
"name": baz,
},
//..stuff
properties : {
"mission": foo2,
"driver": bar2,
"name": baz2,
},
],
In my looped component, I binded my :items="items" and I want to display props like item.properties.mission when my item.label = filters.mission, and so on
But here is the thing :
WORKING
{{ item.properties.mission}} OUTPUT : 'foo', 'foo2'
NOT WORKING
{{ item.properties + label.replace('filters', '') }}
OUTPOUT : [object Object].mission
I tried to parse label.replace('filters', '') but it made me an error.
I also tried to stringify...
Should I write a v-for for my :item object and filter the content ?
item.properties.filter(
(prop) => Object.keys(prop) === label.replace('filters.', ''))
)
If so, where should I filter my object ?
Thanks in advance for anyone answering this !
Because item.properties is an object, you can access mission also using item.properties['mission'].
In your case you can use
{{ item.properties[label.replace('filters', '')] }}
I'm have a project in vuejs, Vuetify and the following library to generate forms dynamically using annotated JSON Schemas:
https://koumoul-dev.github.io/vuetify-jsonschema-form/latest/about
The library is great and do exactly what I need, generate form from JSON scheme, I can even add my own component, and show it on a form, the only missing thing is I cant get the slot component data into the model.
you can find my example here:
https://codepen.io/eran-levi/pen/jOqjroa
This is how I added the component:
<template slot="rating" slot-scope="{key, value, update, schema }" class="field">
<star-rating :value="value" #rating-selected="update($event, key)" :show-rating="false" />
</template>
and in the Schema JSON:
rating: {
type: "number",
title: "Rating",
minimum: 0,
maximum: 5
}
as you can see, once you hit the "Show Data" button, you can see the results of each field you edit, beside the value of the new star component I have added..
what am I missing here?
Thank you.
You are missing your update method.
I added the updateRating method and bound it to the #rating-selected event.
Here is a working fiddle: https://jsfiddle.net/9pjdxht6/1/
vue-star-rating component:
<star-rating :value="value" #rating-selected="updateRating" :show-rating="false" />
updateRating method:
updateRating: function(rating){
this.model.rating = rating;
}
Hope it help you.
Quick Context:
I have a parent Parent.vue that feeds the same list
[{key: "one", selected: false], {key: "two", selected: false}, {key: "three", selected: false]
to multiple components one the same page. None of the items in the list can be selected twice.
What I have tried:
So my parent creates a Child.vue component and passes in this list. Child.vue props accepts it then populates the :items fields of the <v-select>. As a result we see all 3 items. I select "two". I bind to change event so I $emit to parent the key ("two") and the flag (selected: true) so the parent filters out the list so there is only "one" and "three" now. If I were to add another component at this point - all fine - it would only have "one" and "three" to select from. My problem is that when I select this "two" item - it disappears. Primarily because the parent takes this item out. But... how to I make it so it either stays (indicating that this item have been selected) and other components are not able to select it no more? Can I possible disable just this "two" item for selection (in case other components try to select it - they can't).
I can do it easily with plain HTML and JS - with Vue / Vuetify - how can I accomplish that?
You can do this by adding a property called disabled to your item and compute the value of that property based on the selection of other items:
get filteredItems() {
return this.items.map((item) =>
id: item.identifier, // replace this with the items identifier
text: item.text_value, // replace this with your items display text
disabled: this.items.filter((item) => [...this.firstSelection,...this.secondSelection].filter((selection) => selection === item).length > 0)
// ^ replace the above destructured array params with your real v-model bindings
// if the v-models bindings aren't arrays (and the select isn't multiple)
// then there is no reason to destructure that value
})
}
Now modify your v-select component and add a value for the item-disabled property that matches the key that we can lookup in the map:
<v-select :items="filteredItems" item-text="text" item-id="id" item-disabled="disabled"
So what I ended up doing is binding to :item-disabled property- I bind selected to and maintain it from the parent throughout all the child components. It get deselected - I emit the event to the parent saying hey element by id "this" is no longer selected. That in turn refreshes it for all the components that are getting this list through props. Ohgodwhy has a pretty similar solution (thanks!).
For some reason, Vuejs doesn't deeply watch for changes. Let's say below is the data that I'm watching.
input_collection: [
{
type: 'foo',
value: 'foo'
},{
type: 'bar',
value: 'bar'
},{
type: 'baz',
value: 'baz'
}
]
Basically its an array of objects. When I change anything except the last item, it triggers the watch to do its job. But when the last item is updated, it doesn't.
The way that I change the contents of the input_collection is by using v-model and directly changing the value in the code. I'm also suspecting the direct change method as a culprit since i only used this in the last item and the input has a read-only attribute, but since I'm directly assigning a new value for the item's content, that shouldn't be a problem.
//via v-model
<input :type="type" v-model="title"/>
//via directly changing
<input type="type" :value="value" readonly>
//js
this.input.title = new_value;
this.value = new_value;
I tried manually changing the last contents in the last item's content via the Vue Devtools Extension but it still doesn't work.
I have figured it out. Turns out that it being readonly is causing my problems.
I just created a work around to it by doing:
//markup
<input type="text" v-model="input.value" #keypress.prevent>
//js
this.input.value = new_value
Now, the watcher works as it should be.