How to preselect in Vue multiple select js - vue.js

This is the markup for my veu multiselect
and here is the code
<multiselect
v-model="baths"
placeholder="Bath"
track-by="label"
label="label"
:allow-empty="true"
:options="options.baths"
:select-label="''"
:selected-label="''"
:deselect-label="'Remove'"></multiselect>

Just populate the baths data property with the data you wanted to be preselected.
data: {
baths: [],
options: {
baths: [
// baths list here
]
}
},
mounted() {
this.baths.push(this.options.baths[1]);
}
Also you need to set the multiple prop to true:
<multiselect
v-model="baths"
placeholder="Bath"
track-by="label"
label="label"
:allow-empty="true"
:options="options.baths"
:select-label="''"
:selected-label="''"
:deselect-label="'Remove'"
:multiple="true">
</multiselect>
See this example JS Fiddle:
https://jsfiddle.net/0hLexkyz/278/

Related

Vue.js how to check if inputs from child components are filled so parent component can able/disable a button

Hi I'm new to vuejs and I'm struggling figuring it out how to make this work.
I have 3 different child components in a parent component, each one of the child components have multiple text and radio inputs. What I want to acomplish is to be able to disable a button on the parent component if there are empty inputs or not selected radio buttons.
Can someone explain to me how could I approach this? Thank you!.
You are looking for how to emit data, opposite to passing data down through a prop.
Here is a small example for an input field.
Child1.vue
<template>
<p>
Write something:
<input v-model="inputText" />
</p>
<p>{{ inputText }}</p>
</template>
<script>
export default {
data() {
return {
inputText: '',
};
},
emits: ['emitInput'],
watch: {
inputText() {
this.checkContent();
},
},
methods: {
checkContent() {
this.$emit('emitInput', this.inputText === '');
},
},
};
</script>
App.vue (parent):
<template>
<div id="app">
<button :disabled="disabledButton">Parent Button</button>
<Child1 #emitInput="parentMethod" />
</div>
</template>
<script>
import Child1 from './Child1.vue';
export default {
name: 'App',
components: {
Child1,
},
data() {
return {
disabledButton: true,
};
},
methods: {
parentMethod(payload) {
//Since you had a 2nd parameter on line 24 in Child1, you can access it.
//We were checking if input is empty or not, returning a boolean.
this.disabledButton = payload;
},
},
};
</script>

Vue 3 two way binding with select box

I'm trying to create a two way binding between my parent (create user form) and a child component (reusable selectbox).
The parent component
<template>
<Selectbox :selectedOption="selectedRole" :options="roles" />
<span>SelectedRole: {{ selectedRole }}</span>
</template>
<script>
import Selectbox from '#/components/formElements/Selectbox.vue';
export default {
components: {
Selectbox,
},
async created() {
await this.$store.dispatch('roles/fetchRoles');
this.selectedRole = this.roles[0].value;
},
data() {
return {
selectedRole: null,
};
},
computed: {
roles() {
return this.$store.getters['roles/roles'].map((role) => ({
value: role.id.toString(),
label: role.name,
}));
},
},
};
</script>
I'm passing down the roles as options and the selectedRole variable as selectedOption.
The child component
<template>
<select :value="selectedOption" #input="(event) => $emit('update:selectedOption', event.target.value)">
<option v-for="option in options" :value="option.value" :key="option.value">{{ option.label }}</option>
</select>
</template>
<script>
export default {
props: {
options: {
type: Array,
required: true,
},
selectedOption: {
type: String,
required: false,
},
},
};
</script>
The selectedOption is assigned to the value together. When another value is selected I want to update the passed down value in the parent component. Therefore I'm using an $emit function but that's not working right now.
I also tried to use v-model to combine the value and change attributes but without success.
<select v-model="selectedOption">
What's the correct way?
Code: Codesandbox
I guess this is the handling you want to achieve: https://codesandbox.io/s/practical-orla-i8n3t?file=/src/components/Selectbox.vue
If you use v-model on a sub-component, you have to handle it properly in the sub-component.
<custom-select v-model="value" />
<!-- IS THE SAME AS -->
<custom-select
:modelValue="value"
#update:modelValue="value = $event"
/>
So if you use v-model, a property with the name modelValue gets passed down to the sub-component. If the modelValue changes (which means another option in the select list gets selected) you have to emit a change event, indicating that the modelValue got changed: $emit('update:modelValue'). v-model automatically updates it's value if this event occurs.
Source: https://learnvue.co/2021/01/everything-you-need-to-know-about-vue-v-model/

Vue v-model does not select value on checkbox

I'm fairly new to Vue and I've researched as much as I could, but cannot find a solution to this strange issue. I'm building a filter function for an online shop, and one section allows filtering based on values with a checkbox.
My vue template is as following:
<template>
<div>
<h3>{{data.filterLabel}}</h3>
<ul>
<li v-for="(item, index) in data.options" :key="index">
<input v-model="values" type="checkbox" :id="item" :value="item" :index="index" />
<label class="products__label products__capitalize" :for="item">{{ item }}</label>
</li>
</ul>
</div>
</template>
I am getting the options from a database, and loop through the data.options array with v-for. I have created a new empty array in
data() {
return {
values: []
};
},
as in the form-bindings example on the vue.js website here: https://v2.vuejs.org/v2/guide/forms.html#Checkbox
My script is as following:
<script>
export default {
name: "CheckBoxFilter",
data() {
return {
values: []
};
},
props: {
data: Object,
filterCheckBox: Function
},
watch: {
values: function(value) {
const optionRange = JSON.parse(JSON.stringify(this.values));
this.$emit("filterCheckBox", this.data.filterValue, optionRange);
}
}
};
</script>
For some strange reason, the $emit function works perfectly fine, and the array of products is filtered correctly in the UI. But when I check a value in the checkbox, the checkbox is not ticked. How is it possible that the checkbox is not ticked, while at the same time it is clearly correctly filtering the values?
I even looked at the :checked value with $event.target.checked which also correctly returns true or false, but the checkbox is still not ticked in the UI.
I have the same issue with radio buttons.
There are no issues with the <input type="text"> and also no issues with a <select>.
Has anyone experienced this before and if so what is the solution?
Thanks!
I tested and the UI displays the checked/unchecked checkboxes properly. Which version of Vue do you use? I'm not sure of what you want to do, but I think it would be cleaner to expose your values through a computed property:
export default {
name: "CheckBoxFilter",
props: {
data: Object,
},
data() {
return {
internalValues: [],
};
},
computed: {
values: {
get() {
return this.internalValues;
},
set(newVal) {
this.internalValues = newVal;
this.$emit("filterCheckBox", this.data.filterValue, [...newVal]);
},
},
},
};
</script>
With your current implementation, the values change are not observable and the filterCheckBox event is never emitted.
EDIT: I also don't understand why you set a filterCheckBox prop, it is not React ;)

sending drop-down value to parent

I have this form on my parent:
<template>
<b-form #submit="onSubmit">
<CountryDropdown/>
</b-form>
</template>
<script>
import ...
export default {
form: {
country: ''
}
}
</script>
This is my Dropdown component using vue-select:
<template>
<v-select label="countryName" :options="countries" />
</template>
<script>
export default {
data() {
return {
countries: [
{ countryCode: 'EE', countryName: 'Estonia' },
{ countryCode: 'RU', countryName: 'Russia' }
]
}
}
}
</script>
I need to pass the countryCode value to its parent's form.country. I tried using $emit, but I cant seem to figure out how upon selection
it will set the parent value, and not upon submit.
EDIT:
The submitted solutions work great, I'll add my solution here:
I added an input event to my v-select:
<v-select #input="setSelected" ... />
in my script i define the selected and setSelected method :
data()
return
selected: ''
setSelected(value) {
this.selected = value.countryCode
this.$emit("selected", value.countryCode)
}
And in the parent:
<CountryDropdown v-on:selected="getCountry />
and parent script:
getCountry(country) {
this.form.country = country
}
You could use Vue's v-model mechanism to bind the output of vue-select to form.country in the container.
In CountryDropdown, implement v-model:
Add a prop named value 1️⃣, and bind it to vue-select.value 2️⃣
Emit input-event with the desired value. In this case, we want to emit countryCode as the value. 3️⃣
<template>
<v-select
:value="value" 2️⃣
#input="$emit('input', $event ? $event.countryCode : '')" 3️⃣
/>
</template>
<script>
export default {
props: ['value'], // 1️⃣
}
</script>
Now, the container of CountryDropdown could bind form.country to it, updating form.country to the selected country's countryCode upon selection:
<CountryDropdown v-model="form.country" />
demo
As you seem to know, $emit is what you need to use to send an event from a component to its' parent. To make that happen you need to add a few more things to your current code.
To get the options to list in your v-select you should use a computed function to isolate the names, like this:
computed: {
countryNames() {
return this.countries.map(c => c.countryName)
}
},
You will then need to list the names in your v-select like this:
<v-select label="countryName" :items="countryNames" #change="selectedCountry" />
You will see that #change is calling a method, this will be the method to emit your country code and it can do so like this:
methods: {
selectedCountry(e) {
let code = this.countries.find(cntry => cntry.countryName === e)
this.$emit('code', code.countryCode)
}
},
You will need a listener in your parent to hear the emit, so add something like this:
<CountryDropdown v-on:code="countryCodeFunction"/>
And then you just need a countryCodeFunction() in your methods that does something with the emitted code.

Is it possible to use dynamic scoped slots to override column values inside <v-data-table>?

I'm trying to create a reusable table component that utilizes Vuetify's v-data-table component in order to group common aspects such as a search bar, table actions (refresh, create, etc.) and other features that all of my tables will have. However, I'm running into issues with implementing dynamic, scoped slots inside the table component to account for custom columns. Think of columns like actions, formatted ISO strings, etc.
Here's a simplified example of what I'm trying currently. In the example, I am passing the array customColumns to CustomDataTable.vue as a prop. customColumns has one element with two properties. The slotName property specifies the name of the slot that I'd like to reference in the parent component. The itemValue property specifies the header value that CustomDataTable.vue should override and replace with a scoped slot. The scoped slot is then used in the parent component to correctly format the date in the 'Created At' column.
Parent Component that is implementing the table component:
<template>
<custom-data-table
:items="items"
:headers="headers"
:customColumns="customColumns"
>
<template v-slot:custom-column="slotProps">
<span>{{ formatDate(slotProps.item.createdAt) }}</span>
</template>
</custom-data-table>
</template>
<script>
import CustomDataTableVue from '#/components/table/CustomDataTable.vue'
export default {
data: () => ({
items: [
{
id: 0,
createdAt: new Date().toISOString(),
...
},
...
],
headers: [
{
text: 'Created At',
value: 'createdAt',
sortable: true
},
...
],
customColumns: [
{
slotName: 'custom-column',
itemValue: 'createdAt'
}
]
})
}
</script>
CustomDataTable.vue
<template>
<v-data-table
:items="items"
:headers="headers"
>
<template v-for="column in customColumns" v-slot:item[column.itemValue]="{ item }">
<slot :name="column.slotName" :item="item"/>
</template>
</v-data-table>
</template>
<script>
export default {
name: 'custom-data-table',
props: {
items: {
type: Array,
required: true
},
headers: {
type: Array,
required: true
},
customColumns: {
type: Array
}
}
}
</script>
Is there a way to achieve this? The example does not override the column values and just displays the createdAt ISO string unformatted. I believe the problem might be coming from how I'm assigning the template's slot in CustomDataTable.vue, but I'm sure how else you could dynamically specify a template's slot. Any ideas?
I think the syntax for dynamic slots should be:
<template
v-for="column in customColumns"
v-slot:[`item.${column.itemValue}`]="{ item }"
>
<slot :name="column.slotName" :item="item"/>
</template>