"prop" is undefined though it's being passed correctly - vue.js

I've been following VueJS official documentation on passing data to child components with props; though I'm not working with a string template. I'm aware about what happens when your prop is camel case; you should write it as kebab case.
Nevertheless, this is not the case since it's all lowercase and won't work.
I'm using nuxt and I've separated my work into files, which are:
<template>
<div class="row">
<input type="text" name="" id="" placeholder="Write your question" v-model="text">
<select v-model="selectedField">
<option v-for="option in options" :key="option.id" :value="option.value">
{{ option.text }}
</option>
</select>
<button class="btn btn-sm btn-primary" #click="$emit('add-field')"
v-bind:class="{ disabled: ($parent.count <= 1 && $parent.count == identifier) }">
>{{identifier}}</button>
<button class="btn btn-sm btn-danger" #click="$emit('delete-field')">-</button>
</div>
Now for its JS file:
export default {
data () {
return {
options: [
{
id: 1,
value: 1,
text: "Radio"
},
{
id: 2,
value: 2,
text: "Rate"
},
{
id: 3,
value: 3,
text: "Text"
}
],
props: ['identifier'],
selectedField: 1,
text: "",
}
},
}
Now, for my parent component:
<template>
<div class="offset-md-3" id="qz">
<form-maker
v-for="item in questions" :key="item._id"
v-on:add-field="addField()"
v-on:delete-field="deleteField(item._id)"
v-bind:identifier="item._id" <<--What I want to set
ref="child"
></form-maker>
<button #click="saveForm" class="btn btn-large btn-success">SAVE</button>
</div>
</template>
Finally:
var vm = null;
export default {
layout: 'admin',
components: {
formMaker
},
data() {
return {
count: 1,
questions: [{
_id: 1//static
}]
}
},
}
What I'm trying to do is, to use the prop for some validations, nevertheless it throws the next error:
Property or method "identifier" 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.
Thank you.

Here is where you go wrong. Props should not be in data(). See the code snippet below
<script>
export default {
props: ['identifier'],
data() {
return {
options: [
{
id: 1,
value: 1,
text: "Radio"
},
{
id: 2,
value: 2,
text: "Rate"
},
{
id: 3,
value: 3,
text: "Text"
}
],
selectedField: 1,
text: "",
}
}
}
</script>

Related

How do I pass a data attribute in vue js select option

I need to pass a select object data attribute to a function on change. I can pass the value fine, but how can i pass the 'test' attribute below? e.target.test returns undefined.
<select v-model="prog.programme_id" #change="updateTest">
<option v-for="programme in programmes" :key="programme.id" :value="programme.programme_id" :test="programme.newval">{{ programme.title }} )</option>
</select>
method:
updateTest(e){
console.log(e.target.value)
},
event.target refers to the SELECT not the options... you have to select the selected option and get it's attribute
event.target.options[event.target.options.selectedIndex].getAttribute('test')
here is the full component example
<template>
<div>
<select v-model="val" #change="updateTest($event)" style="width: 100px" test="Test">
<option v-for="programme in list" :key="programme.id" :value="programme.id" :test="programme.name">{{ programme.value }} )</option>
</select>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
val: null,
list: [
{id: 1, name: "John", value: "A"},
{id: 2, name: "Jack", value: "B"},
]
}
},
methods: {
updateTest(event) {
console.log(event.target.options[event.target.options.selectedIndex].getAttribute('test'))
}
}
}
</script>
<style scoped>
</style>

Datalist disapearing in a simple vue example

Try to select from datalist while a data property is updated on a interval.
What is wrong in my code?
http://jsfiddle.net/startflorin/gr6b1h7j/18
Mounted intervals:
setInterval((ctx) => { ctx.notification = "111"; }, 500, this);
setInterval((ctx) => { ctx.notification = "222"; }, 500, this);
Data:
data: {
notification: null,
demoList:[
{
id: 1,
name: "option 1",
},
{
id: 2,
name: "option 2",
},
{
id: 3,
name: "option 3",
},
],
},
My HTML code:
<div>
{{ notification }}
</div>
<input list='demoList' v-on:change="selectSymbolList(target.value)">
<datalist id="demoList">
<option v-for="item in this.demoList" v-bind:value="item.name" v-bind:key="item.id">{{ item.name }}</option>
</datalist>
To cache the rendering of <input> and <datalist> (to isolate them from unrelated changes in the component's template), put them into a component:
Vue.component('demo-list', {
props: ['items'],
template: `<div>
<input list='demoList'>
<datalist id="demoList">
<option v-for="item in items" v-bind:value="item.name" v-bind:key="item.id">{{ item.name }}</option>
</datalist>
</div>`
})
Note this example requires the runtime compiler to compile the template string. Otherwise, render functions would be required instead of template.
Then use the component in your app's template:
<div id="app">
<div>{{ notification }}</div>
<demo-list :items="demoList"></demo-list>
</div>
demo

Emitting two properties from child to parent

Can anyone help with this problem? How can I emit two properties from child component to parent on select input change? I can submit the value, see below, but would like to emit the value and the name property of segmentLocations object. This is the child component:
<template>
<div class="container">
<div>
<select v-model="selectedSegmentValue" v-on:change="$emit('selectLocation', $event.target.value)">
<option selected value="">Choose your location...</option>
<option v-for="segmentLocation in segmentLocations"
:value="segmentLocation.value"
:key="segmentLocation.value">
{{ segmentLocation.name }}>
</option>
</select>
</div>
</div>
</template>
<script>
export default {
data() {
return {
segmentLocations: [
{ value: "Residential", name: 'Residential building' },
{ value: "Workplace", name: 'Workplace' },
{ value: "Hospitality", name: 'Hospitality or Retail' },
{ value: "Real Estate", name: 'Real Estate' },
{ value: "Commercial Parking", name: 'Commercial Parking' },
{ value: "Fleets", name: 'Fleets' },
{ value: "Cities & Governments", name: 'Cities & Governments' },
{ value: "Corridor", name: 'Highway, Corridor or Petrol Station' }
],
}
}
};
</script>
And this is the parent:
<template>
<Segments
v-on:selectLocation="quote.selectedSegmentValue = $event"
:selectedValue="quote.selectedSegmentValue">
</Segments>
</template>
<script>
export default {
data() {
return {
quote: {
selectedSegmentValue: "",
selectedSegmentName: ""
},
};
},
</script>
I think the existing answers and mine share a similar technique, but I created a couple of simplified sample components based on your components.
Child component:
<template>
<div class="emit-two-properties">
<div class="form-group">
<label for="segment-location">Segment Location</label>
<select class="form-control" id="segment-location"
v-model="segmentLocation" #change="selectSegmentLocation">
<option v-for="(segLoc, index) in segmentLocations" :key="index"
:value="segLoc">{{ segLoc.name }}</option>
</select>
</div>
</div>
</template>
<script>
export default {
data() {
return {
segmentLocation: {},
segmentLocations: [
{ value: "Residential", name: 'Residential building' },
{ value: "Workplace", name: 'Workplace' },
{ value: "Hospitality", name: 'Hospitality or Retail' },
{ value: "Real Estate", name: 'Real Estate' },
{ value: "Commercial Parking", name: 'Commercial Parking' },
{ value: "Fleets", name: 'Fleets' },
{ value: "Cities & Governments", name: 'Cities & Governments' },
{ value: "Corridor", name: 'Highway, Corridor or Petrol Station' }
],
}
},
methods: {
selectSegmentLocation() {
this.$emit('select-segment-location-event', this.segmentLocation);
}
}
}
</script>
Parent component:
<template>
<div class="parent">
<h4>Parent.vue</h4>
<div class="row">
<div class="col-md-6">
<form #submit.prevent="submitForm">
<emit-two-properties #select-segment-location-event="updateSegmentLocation" />
<button class="btn btn-secondary">Submit</button>
</form>
<p><span>Selected Segment Location Value:</span>{{ segmentLocation.value }}</p>
<p><span>Selected Segment Location Name:</span>{{ segmentLocation.name }}</p>
</div>
</div>
</div>
</template>
<script>
import EmitTwoProperties from './EmitTwoProperties'
export default {
components: {
EmitTwoProperties
},
data() {
return {
segmentLocation: {}
}
},
methods: {
updateSegmentLocation(segLoc) {
this.segmentLocation = segLoc;
}
}
}
</script>
you can create a method to get name and value from event.target (remove value from the end of child emit):
changeSelectedSegment(selected){
this.selectedSegmentName = selected.name
this.selectedSegmentValue = selected.value
}
in the parent change v-on:selectLocation to v-on:selectLocation="changeSelectedSegment($event)"
you can define a method like this (this method emit an object with name and value properties to parent
)
methods: {
selectLocation(event){
if(event.target.value !== ''){
const item = this.segmentLocations.find( item => item.value === event.target.value)
this.$emit('selectLocation', {
name: item.name,
value: event.target.value
})
}
}
},
and change this line :
<select v-model="selectedSegmentValue" v-on:change="$emit('selectLocation', $event.target.value)">
to this:
<select v-model="selectedSegmentValue" v-on:change="selectLocation">

VueJS show multiple input fields conditionally

I have a 'Add' button which adds a select box and when I select a value in the select box I want to display an input field so every time I click 'Add' it should show a select box and when I select a value in it I would like to display an input field.
I know I could use a flag 'selected' but when I already add one select box this would change the flag to true and show the input field immediately after I click 'Add' but I want the input field to show only when a value is selected.
<template>
<button #click="onBtnClick">Add<button>
<select>...</select> # This gets added when 'Add' button is clicked
<input v-if="selected" type="text" /> # This should show when a value is selected.
<select>
</template>
data(){
return {
selected: false
}
},
methods: {
onValueSelected(){
this.selected = true
}
}
Do you have any ideas how I could accomplish this?
Use v-for and push new fields onto the collection at will.
new Vue({
el: '#app',
data() {
return {
goods: []
}
},
methods: {
addSelect() {
let item = {
id: this.goods.length,
menus: [
{ value: '', text: '- select -' },
{ value: 1, text: 'Item 1' },
{ value: 2, text: 'Item 2' },
{ value: 3, text: 'Item 3' }
],
input: {
show: false
}
};
this.goods.push(item);
},
showInput(item, e) {
item.input.show = e.currentTarget.selectedIndex > 0;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="addSelect">Add to cart</button>
<div v-for="item in goods" :key="item.id" class="goods">
<select #change="showInput(item, $event)">
<option
v-for="opt in item.menus"
:key="opt.key"
value="opt.value">
{{opt.text}}
</option>
</select>
<input v-if="item.input.show" type="text" value="0" />
</div>
</div>
I figured out that I can render a new component and pass it props. Everytime a new component is rendered it gets selected flag as false by default and I can change it then by selecting a value in the select box.
<b-form-group
v-if="element.elementName === 'Some value'"
label="Select field *:"
label-for="benefitSelectField">
<SalaryField :element="element" />
</b-form-group>
SalaryField component
<template>
<div>
<select #change="onValueSelected" ></select>
<input v-if="selected" type="text" />
</div>
</template>
<script>
export default {
props: {
element: Object
},
data(){
return {
selected: false,
}
},
methods: {
onValueSelected() {
this.selected = true
}
}
}
</script>

Vue.js - Select / dropdown selected item vm binding is not working (bootstrap-vue)

I'm trying to create a simple vue that binds the selected item from a select/dropdown to a property in the vm.
I haven't been able to find a clear and simple example of how this is down when using an options collection that is also in the view model.
<template>
<div>
<h1>Select box</h1>
<b-dropdown id="ddCommodity"
name="ddCommodity"
v-model="ddTestVm.ddTestSelectedOption"
text="Select Item"
variant="primary"
class="m-md-2" v-on:change="changeItem">
<b-dropdown-item disabled value="0">Select an Item</b-dropdown-item>
<b-dropdown-item v-for="option in ddTestVm.options":selected="option.value == 'LME/ST_TNI_ALL'":value="option.value">{{option.text}}</b-dropdown-item>
</b-dropdown> <span>Selected: {{ ddTestVm.ddTestSelectedOption }}</span>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {
someOtherProperty: null,
ddTestVm: {
originalValue: [],
ddTestSelectedOption: "Value1",
disabled: false,
readonly: false,
visible: true,
color: "",
options: [
{
"value": "Value1",
"text": "Value1Text"
},
{
"value": "Value2",
"text": "Value2Text"
},
{
"value": "Value3",
"text": "Value3Text"
}
]
}
}
},
methods: {
changeItem: async function () {
//grab some remote data
try {
let response = await this.$http.get('https://www.example.com/api/' + this.ddTestVm.ddTestSelectedOption + '.json');
console.log(response.data);
this.someOtherProperty = response.data;
} catch (error) {
console.log(error)
}
}
},
watch: {
},
async created() {
}
}
</script>
<style>
</style>
Regardless of what i've tried i cannot get the selected value in the dropdown to change the ddTestSelectedOption property of the vm.
Could anyone assist on this issue?
Thanks.
b-dropdown in bootstrap-vue does not support v-model. As the documentation states:
Dropdowns are toggleable, contextual overlays for displaying lists of
links and actions in a dropdown menu format.
In other words, b-dropdown is essentially a UI component for displaying a menu or similar set of options.
I expect what you want is b-form-select.
That said, you could add a click handler to the options that sets the value.
<b-dropdown-item v-for="option in ddTestVm.options"
:key="option.value"
:value="option.value"
#click="ddTestVm.ddTestSelectedOption = option.value">
Here is a working example.
I thing you need b-form-select
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
<b-form-select v-model="selected" :options="options" size="sm" class="mt-3"></b-form-select>
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: null, text: 'Please select an option' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Selected Option' },
{ value: { C: '3PO' }, text: 'This is an option with object value' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
Only b-form-select can achieve the selected value behaviour.
Non-Selected Value Preview:
Selected Value Preview:
Sample Code:
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: 1, text: 'Please select an option' },
{ value: 2, text: 'This is First option' },
{ value: 3, text: 'Selected Option' }
]
}
}
}
</script>
Wanted to leave a comment, but code example looks pale there :)
Yes, b-dropdown does not properly support Vue model, but it doesn't have to.
For those still interested in exactly dropdown (f.e. because it looks fancier), consider:
<b-dropdown :text="$i18n.locale" >
<b-dropdown-item v-for="(lang, i) in $i18n.availableLocales" :key="`Lang${i}`" :value="lang" v-on:click="$i18n.locale = lang;" >{{lang}}</b-dropdown-item>
</b-dropdown>
Slecifically v-on:click, which can handle the model value change for you.