Multiple VueSelect - vue.js

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"
/>

Related

How can I correctly set a checkbox as checked using an array of objects

The value(s) are being stored correctly—the v-model is correct, I'm just having trouble getting the checkboxes to be checked or not.
Here is my template:
<input type="checkbox"
v-for="thing in things"
:value="thing.id"
v-model="$v.thing.activities.$model"
:checked="$v.thing.activities.$model.some((el) => el.id === thing.id)"
/>
I am using NestJs to handle saving my data. There is a many:many relationship, so the system returning the entire object.
Here is what my v-model looks like. It's an array of objects:
[
0:Object
createdAt:""
description:"This is what thing is."
id:"07347f64-..."
name:"Thing"
updatedAt:""
]
When I click on a checkbox, I can see that the v-model is updated properly with the new id which is great.
I know it's working properly, when I do this on my template to test, it renders true or false as expected:
{{ $v.thing.activities.$model.some((el) => el.id === thing.id) }} // true
I see in the vue docs that v-model will take precedence over :checked, but since my v-model is an array of objects, I'm not sure how to set the checked property of the checkbox.
I've also tried pulling the current loop value and creating a temporary array push/splice values out to get the checkbox to render properly in a created hook. No luck there either. I think everything needs to come from the v-model, but I'm at a loss.
How can I correctly show the checkbox as checked?

Vue can't render curly brackets + value

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', '')] }}

Console error because store variable used in template only gets populated after async API call

In my component I display many properties (only showing two below) of my selectedPlan store variable after getting its value from the store:
<div>
{{ selectedPlan.periodTitle }}
</div>
<div>
{{ selectedPlan.currency }}
</div>
...mapGetters(['selectedPlan', 'whatever'])
Problem: this variable is null by default and only gets populated after some unrelated component makes an API call.
The variable does get displayed so no problem on screen. But in console I get:
TypeError: Cannot read property 'periodTitle' of null
How to fix this problem?
Since selectedPlan may not be available(or has null value) on the first render, you are facing that error. You have one of three ways to solve this issue:
Add a loader and wait until selectedPlan is available (best way in my opinion from the UX perspective)
Add a null check before accessing values like:
{{ (selectedPlan || {}).periodTitle }}
Or much better, use a computed property:
computed: {
safeSelectedPlan: () => {
return this.selectedPlan || {}
}
}
and then use safeSelectedPlan in your template.
Use a library like lodash to get the values for variables safely.
Here is the documentation link to lodash: https://lodash.com/docs/4.17.15

bootstrap-vue editable table revert value if error

I am using the vue js and bootstrap-vue to make an editable table, the user is allowed to make changes on the table with v-on:change assisting to axios update the database. The restriction is that the Languages are Unique and cannot be an empty string, I cannot seem to be able to revert the value if the user makes a mistake. What is the recommended approach to this? Any help is greatly appreciated.
I have tried to "refresh" the table by doing:
this.languages = this.languages;
Does not seem to refresh the value in the table.
a section of vue component on the table:
<b-table striped hover :items="filtered" :fields="fields">
<template slot="name" slot-scope="data">
<b-form-input type="text" :value="data.item.name" v-on:change="updateLanguage($event,data.item.id)"></b-form-input>
</template>
</b-table>
in the methods of vue export default:
updateLanguage(e,id) {
if(e.trim()){
const find_langauge = this.languages.find(language=>{
return language.name.toLowerCase() === e.toLowerCase();
});
find_langauge ? this.languages = this.languages : console.log('no match');
} else {
console.log('cannot be empty');
this.languages = this.languages;
}
}
in computed:
filtered() {
return this.search ? this.languages.filter(language=>
language.name.toLowerCase().includes(this.search.toLowerCase())) : this.languages;
}
I cannot find any solution to refresh the :value, so I ended up with force re-render of the component. Not ideal, but at least the entire component got refreshed. Will appreciate any better way to approach this instead of re-rendering.
Vue doesn't retain "initial" values for inputs, as it relies on your data modal as the source of truth.
You would need to store the initial value in data, and when detecting a reset, copy that initial value back to the v-model associated with the input.
Also, if you have inputs in multiple rows, it is a good idea to set a unique key on the input, and or if you have a unique key field (where the value is unique per item row), set the primary-key prop on b-table to have it generate a unique Vue key per TR element.

How to get an object rather than a single value when clicking on a v-select item?

My v-select's data is an array of objects. For each item, the value is one property and the text for that item is a different property. However I really need to retrieve both, not just the value.
So I guess I need to retrieve the object. Is it possible?
V-select code:
<v-select
:items="projects"
v-model="project"
item-text="projectName"
item-value="projectId"
solo
></v-select>
This is how the array of items is populated (in mounted hook):
querySnapshot.forEach((doc) => {
let data = {
'projectId': doc.id,
'projectName': doc.data().name,
'clientId': doc.data().clientId
}
this.projects.push(data);
});
Add return-object prop:
<v-select return-object>
See docs:
https://vuetifyjs.com/en/components/selects#example-custom-text-and-value