I have the following vuejs code:
<select v-model='selectedInverter' class="custom-select" #change="changedInverter">
<option>Select an inverter</option>
<template v-for="inverter in localInverters">
<option>{{inverter.display_name}}</option>
</template>
</select>
If I console.log(this.selectedInverter) in my changedInverter, I get just the display_name and not the whole object. How do I capture (or bind) the whole object in v-model?
The documentation on this is here: https://v2.vuejs.org/v2/guide/forms.html#Select
If you scroll down to the dynamic options section you'll see example code that will get you where you need to be:
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
In your case, your v-bind:value data will be the entire inverter object, where the option text would be {{inverter.display_name}} as you already have in place.
Related
I'm new to Vue and am trying to build a form with a datalists. The code I've written seems to work fine but I'm not sure why the dropdown list will appear twice. Once when nothing is typed into the input where it will show all the options available, and the second time when an option is chosen and the dropdown will show only the options that match the one typed. Is there a way to get rid of the second dropdown, where it will only show the dropdown once?
Template
<input list=list1 v-model="test">
<datalist id=list1>
<option v-for "item in items" :value="item" :key="item"></option>
</datalist>
Script
export defaults{
data(){
items: [1,2,3,4,5],
test: ''
}
}
Try using {{ item }} instead of binding :value to show and populate the value.
<div>
<input type="text" list="list1" v-model="test" #change="onChange()" />
<datalist id="list1">
<!-- use normal {{ item }} here without binding value-->
<option v-for="item in items" :key="item">{{ item }}</option>
</datalist>
</div>
I'm trying to implement 1-way binding. What I want is that changing dropdown should affect the text in <p> and the text. Change tag should effect only text within <p>. But when I change the dropdown value, I lost the value within the <p> as well as within the tags
<span class="wt-select">
<select id="student_skill" v-model="selected">
<option v-for="(stored_skill, index) in stored_skills" :key="index.id" :value="stored_skill.id">{{stored_skill}} hours</option>
</select>
<p>{{ selected }}</p>
<input :value="selected" type="text" class="form-control" id="date_time">
</span>
How can I achieve this? I tried the following link, but still unable to achieve this one-way binding:
Vue.js get selected option on #change
The following code will report an error:key duplication
<option-group
v-if="dataSource[0] && dataSource[0].options"
v-for="item in dataSource"
:key="item.label"
:label="item.label"
>
...
</option-group>
<Option
v-else
v-for="option in dataSource"
:label="option.label"
:value="option.value"
:key="option.value"
></Option>
but following code will not report the error, when I wrap the code with 'template' label:
<template v-if="dataSource[0] && dataSource[0].options">
<option-group
v-for="item in dataSource"
:key="item.label"
:label="item.label"
>
...
</option-group>
</template>
<template v-else>
<Option
v-for="option in dataSource"
:label="option.label"
:value="option.value"
:key="option.value"
></Option>
</template>
I want to know why?
It's because in your first example both the option-group and Option components are rendered thus same key is in two different elements, one in option-group and one in Option.
Both are rendered because you used v-for and v-if at the same time. It is not recommended because
VueJS prioritizes the v-for directive over the v-if directive. So under the hood, it loops through every element and THEN checks the v-if conditional.
You can read more about it here
Take the following code which is essentially going to render a form stepper and for the purposes of simplifying my example I have included just one step:
<form-wizard :formdata="this.form_data">
<form-tab stepindex="1" title="Title of Tab" :selected="true">
<div class="col-md-11 col-lg-10">
<div class="form-group">
<label for="OptionType" class="sr-only">Option Type</label>
<select v-model="form_data.optionType" #change="onChangeOptionType" id="OptionType">
<option value=""/>
<option v-for="option in form_data.fees" v-bind:value="option.cost">
{{ option.text }}
</option>
</select>
</div>
</div>
</form-tab>
</form-wizard>
For reasons I cannot understand the values are bound to the select options as expected and without error however the option text throws an error in the browser console that I cannot seem to overcome.
Property or method "option" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
It's like for some reason it is looking out to the wider scope for the option rather than the option in the v-for loop.
I'd appreciate any advice on how to correct this but also any help to try and understand why this is even the case.
If any additional information is required to help answer please let me know.
maybe the problem is v-bind:key on v-for
<select v-model="form_data.optionType" #change="onChangeOptionType" id="OptionType">
<option value=""/>
<option v-for="(option, i) in form_data.fees" v-bind:key="i" v-bind:value="option.cost">
{{ option.text }}
</option>
</select>
So I was wondering why this v-if and v-else statement did not work and why I to tackle it a different way.
The code is as follows
<select v-else v-model="experiment.workflow" required>
<option selected :value="null">Required: Select a Workflow {{ isChain ? 'Chain' : '' }}</option>
<option
v-if="isWorkflowChain"
v-for="workflow of data.workflows"
:key="workflow.uuid"
:value="workflow"
{{ workflow.head.name }}>
</option>
<option
v-else
v-for="workflow of data.workflowChains"
:key="workflow.uuid"
:value="workflow"
</option>
So I was given this piece of code and it looks like when loading in the data in the v-if statement was fine and the values showed in the drop down menu. When I set the value to
export default {
props: {
isWorkflowChain: {
type: Boolean
value: false
}
}
}
What should have occurred was that it should have skipped the v-if element and head into the v-else (Which I believe it does) and populate the data but the v-for statement doesn't populate the data. From first glance does anyone have any thoughts as to why?
This is a valid question, since it's not obvious that a mix of v-for with v-else is currently not supported.
note the closed feature request at
https://github.com/vuejs/vue/issues/4174
Reason
The problem is that v-for has higher priority and therefor is handled first, and v-if is handled second. That means, not only is the v-if executed on every item, but more importantly in the context of this question, it cannot access the v-else outside of the v-for.
Read more here: https://v2.vuejs.org/v2/style-guide/#Avoid-v-if-with-v-for-essential
Solution
The correct way would be isolate the two blocks, and put the v-if on a higher level, non-rendering <template> component.
<option>
<template v-if="isWorkflowChain">
<option v-for/>
</template>
<template v-else>
<option v-for/>
</template>
</option>
The quicker way to do it is to use an opposite conditional (!isWorkflowChain) with a v-for like this though.
<select v-else v-model="experiment.workflow" required>
<option selected :value="null">Required: Select a Workflow {{ isChain ? 'Chain' : '' }}</option>
<option
v-if="isWorkflowChain"
v-for="workflow of data.workflows"
:key="workflow.uuid"
:value="workflow"
>{{ workflow.head.name }}</option>
<option
v-if="!isWorkflowChain"
v-for="workflow of data.workflowChains"
:key="workflow.uuid"
:value="workflow"
>{{ workflow.head.name }}</option>
</select>
and you can make isWorkflowChain a computed. If you have multiple statements and want to capture the else, it gets a bit trickier, but you can put that logic into a computed.
Vue 3 - Breaking Change
In Vue 3 v-if will have higher precedence than v-for:
https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html#overview
Computed Properties
However, it is recommended to avoid using both on the same element, and instead of dealing with this at the template level, one method for accomplishing this is to create a computed property that filters out a list for the visible elements:
computed: {
isWorkflowChain: () => {
// do filtering
}
}
Template
<option v-for="workflow in isWorkflowChain">
{{ workflow.head.name }}
</option>
Docs: https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html#introduction
you need to close <option>, forget > of v-if option :
your code :
<option
v-if="wf = 'workflow'"
v-for="workflow of data.workflows"
:key="workflow.uuid"
:value="workflow" // here where `>` is missing
{{ workflow.head.name }}
</option>
what it's should be :
<option
v-if="wf = 'workflow'"
v-for="workflow of data.workflows"
:key="workflow.uuid"
:value="workflow">
{{ workflow.head.name }}
</option>