How to initialize a select with a selected value? - vue.js

I have a parent component which calls a child component.
The parent :
<select-school-type class="form-control" required value="this.school_type_id" #selected="changeSchoolTypeId">></select-school-type>
The child :
<select v-on:change="$emit('selected', $event.target.value)" v-model="value">
<option value="">{{ placeholder }}</option>
<option :value="schoolType.id" v-for="(schoolType, index) in schoolTypes" :key="index">{{ schoolType.id }}</option>
</select>
The parent can "send" a value to the child (it is the props I called 'value'). And the child must add the "selected" option to the correct item.
I tried a lot of things without success. It is my first components.

value="this.school_type_id"
this is not defined in the template area:
<select-school-type class="form-control" required value="school_type_id" #selected="changeSchoolTypeId"></select-school-type>
If you pass the prop without using:, (value="school_type_id") school_type_id will be type of string. But here we like to pass the variable school_type_id → :value="school_type_id"
v-model in the child changes the prop value, which isn't allowed by vue. You should see a warning in the console: "Avoid changing props directly ....". Change it this way and perhaps it works as expected:
<select #change="$emit('selected', $event.target.value)" :selected="value">
<option value="">{{ placeholder }}</option>
<option :value="schoolType.id" v-for="(schoolType, index) in schoolTypes" :key="index">{{ schoolType.id }}</option>
</select>
If you like to use v-model instead, you can bind a computed getter/setter to it's value: https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter
In the setter, you emit the new value:
computed: {
selectedValue: {
get() {
return this.value;
},
set(newValue) {
this.$emit('selected', newValue);
},
},
},
<select v-model="selectedValue">
<option value="">{{ placeholder }}</option>
<option :value="schoolType.id" v-for="(schoolType, index) in schoolTypes" :key="index">{{ schoolType.id }}</option>
</select>

Related

How to get ID from object when using Vue v-for

I have a select with options created using a Vue.js v-for loop. This works fine but the issue I am having is taking and ID of the option and assigning that to my v-model
What's in my data property
mplans: [
{
name: 'silver',
id: 'silver-m-2019-07-16'
},
{
name: 'gold',
id: 'gold-m-2019-07-16'
},
],
My select
<select class="form-control" v-model="plan">
<option disabled hidden>Select A Plan</option>
<option v-for="plan in mplans">{{ plan.name }} - Monthly</option>
</select>
You can do this to get the ID from the selected option
<select class="form-control" v-model="plan">
<option disabled hidden value="">Select A Plan</option>
<option v-for="p in mplans" :value="p.id" :key="p.id">
{{ p.name }} - Monthly
</option>
</select>
Note: I've changed the v-for "plan" for "p", it can be ambiguous

Vue v-for loop binding attribute

I'm trying to figure out how to do this in vue, I'm stuck trying to bind the value of the "selected" in the options.
In the simplified code below, I get exactly what I want, but only for the first product. It binds correctly with the first computed property:
<template>
<div>
<div v-for="index in 2" :key="index">
<select>
<option :selected="product1 === ''">Empty</option>
<option
v-for="(product, index) of products"
:key="index"
:selected="product1 === product.name"
>{{product.name}}</option>
</select>
</div>
</div>
</template>
<script>
// chosen products come from vuex store
computed: {
product1() {
return store.state.product1;
},
product2() {
return store.state.product2;
},
}
</script>
But then how can I change this to be automatic in the v-for loop, probably using the index?
What I need is actually a loop that will render this:
<template>
<div>
<select>
<option :selected="product1 === ''">Empty</option>
<option
v-for="(product, index) of products"
:key="index"
:selected="product1 === product.name"
>{{product.name}}
</option>
</select>
<select>
<option :selected="product2 === ''">Empty</option>
<option
v-for="(product, index) of products"
:key="index"
:selected="product2 === product.name"
>{{product.name}}
</option>
</select>
</div>
</template>
I've tried using something like:
:selected="`product${index}` === product.name"
but that gives a string, not the computed property value...
you can pass parameter to your computed property:
<template>
<div>
<div v-for="index in 2" :key="index">
<select>
<option :selected="getProduct(index) === ''">Empty</option>
<option
v-for="(product, index) of products"
:key="index"
:selected="getProduct(index) === product.name"
>{{product.name}}</option>
<script>
// chosen products come from vuex store
computed: {
getProduct() {
return index=>
store.state['product'+index];
},
}
</script>
You can put the selected products in an array and then access it by index:
computed: {
selectedProducts () {
return [store.state.product1, store.state.product2];
}
}
And then you can do :selected="selectedProducts[index] === product.name".

Vue.js v-bind:value to empty object

I have a dropdown that is populated with an array of objects.
<select v-model="selectedLeague" v-on:change="chooseLeague()">
<option v-for="league in model.leagues" v-bind:value="league">
{{ league.name }}
</option>
</select>
At initialization, selectedLeague is {}
I want to add a default option that is selected when the object is empty. I tried adding
<option disabled v-bind:value=null>Choose League</option>
But that will not work because it is never null. What can I add to check if the object is empty using data binding? I am using version 2.4.4 btw
Since selectedLeague is initially {}, you can use:
<option disabled v-bind:value="{}">Choose League</option>
Demo:
new Vue({
el: '#app',
data: {
selectedLeague: {},
model: {
leagues: [{name: 'leagueOne'},{name: 'leagueTwo'}]
}
},
methods: {
chooseLeague() { console.log('chooseLeague()', this.selectedLeague); }
}
})
<script src="https://unpkg.com/vue#2.4.4"></script>
<div id="app">
<select v-model="selectedLeague" v-on:change="chooseLeague()">
<option disabled v-bind:value="{}">Choose League</option>
<option v-for="league in model.leagues" v-bind:value="league">
{{ league.name }}
</option>
</select>
</div>
Note: you can also add hidden if you want to hide that option from the dropdown:
<option disabled v-bind:value="{}" hidden>Choose League</option>

VueJS and Drop down values

Am I grabbing the value of the selection incorrectly in this Vue template form?
<select class="form-control" v-model="object.property">
<option selected="selected" value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
</select>
You are binding the value of object.property to the select element correctly.
But, Vue is going to ignore the selected attribute on the first option element.
Here's the warning you will get if you try to use this template:
inline selected attributes on <option> will be ignored when using v-model. Declare initial values in the component's data option instead.
So, if you want the initial value of the select to be the first option, set object.property to that value when you define it in the data method.
Here's an example:
new Vue({
el: '#app',
data() {
return { object: { property: "Option 1" } }
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<select class="form-control" v-model="object.property">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
</select>
{{ object.property }}
</div>

VueJS bind select to object but still POST string

What is the correct way to bind a select element to an object (rather than a string value) but still have the HTML element submit a string value?
I've managed to get this working, but it almost seems like I'm exploiting a bug:
<select v-model="selected" v-on:change="price=selected.price">
<option v-for="item in items" v-bind:value="item" value="{{ item.id }}">{{ item.name }}</option>
</select>
This works as intended: the "selected" property is attached to the "item" object, but the form POSTs just the item's ID. However, if I reverse the order of the HTML attributes, so that value={{ item.id }} comes before v-bind:value="item", then the form POSTs "[Object]" rather than, e.g., "3".
The fact that it's so fragile makes me think I'm doing something wrong.
So what's the right way to handle this?
I had a similar situation in which I built several vue components that could be used both within a vue component or within a standard form.
<select v-model="selected" v-on:change="price=selected.price">
<option v-for="item in items" :value="JSON.stringify(item)">{{ item.name }}</option>
</select>
Appears to be what you are after. I also had success using a computed property or filter but I decided that stringify was most readable.
I fixed it by using this approach:
<select v-model="product">
<option v-for="obj in choices" :value="obj">{{ obj.name }}</option>
</select>
<input type="hidden" name="product" :value="choice.id">
In summary: don't give your select a name but give that name to your hidden input and provide the ID as value on that element instead.
I see in both the cases, HTML being rendered as following:
<select>
<option value="[object Object]">name1</option>
<option value="[object Object]">name2</option>
<option value="[object Object]">name3</option>
<option value="[object Object]">name4</option>
</select>
Case 1 : v-bind:value="item" value="{{ item.id }}" : fiddle
Case 2 : value="{{ item.id }}" v-bind:value="item" : fiddle
So both the cases are equivalent as far as HTML being rendered. Ideal way to do it without confusion will be just using v-bind:value="item" like following:
<select v-model="selected" v-on:change="price=selected.price">
<option v-for="item in items" v-bind:value="item">{{ item.name }}</option>
</select>
You should v-bind to item or item.id depending on what you want to assign to selected variable.