I'm new to Vue.js and trying to build a small application that a user can select a number and view it in another page. The data passed from the parent component was not displayed in the child component like "You select: (a number)", it showed "You select:", without the number passed from the parent. Where did I do wrong? I really can't figure it out.
ParentComponent.vue
<template>
<div>
<p>Select a number:
<select v-model="num">
<option disabled value="">Select</option>
<option v-for="n in 10">{{n}}</option>
<child-component v-bind:select="num"></child-component>
</select>
</p>
</div>
</template>
<script>
import ChildComponent from '../components/ChildComponent'
export default {
name: 'ParentComponent',
components: {
"child-component": ChildComponent
},
data () {
return {
num: 0,
}
}
}
</script>
<style scoped>
</style>
ChildComponent.vue
<template>
<div>
<h2>{{msg}}</h2>
<p>You select: {{select}}</p>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
props: {
select: Number
},
data () {
return {
msg: 'ChildComponent'
}
}
}
</script>
<style scoped>
</style>
You can't use <child-component> in the <select></select> tags, please pull out it from the select tag and run it.
<template>
<div>
<p>Select a number:
<select v-model="num">
<option disabled value="">Select</option>
<option v-for="n in 10">{{n}}</option>
</select>
<child-component v-bind:select="num"></child-component> /// run it in here//
</p>
</div>
</template>
<script>
import ChildComponent from '../components/ChildComponent'
export default {
name: 'ParentComponent',
components: {
"child-component": ChildComponent
},
data () {
return {
num: 0,
}
}
}
</script>
<style scoped>
</style>
Related
Im trying to use a selected option value. Can't show the value or save it.
This is my child component
`
<script>
export default {
props: {
options : {
type:Array,
},
selectOpt:undefined,
}
emits : ['input','change','option:selected']
}
</script>
<template>
<div>
<h1>
Hi, I'm a component
</h1>
<select
v-model="selectOpt"
#change="$emit('input', event.target.value)">
<option v-for="option in options"
:key="option"
>{{option}}</option>
</select>
</div>
</template>
`
This is my parent
`
<script >
import Comp from './Comp.vue'
export default {
data() {
return {
options : [1,2,3,4,5,6],
optSelected : undefined,
}
},
components: {
Comp
}
}
</script>
<template>
<Comp v-model="optSelected" :options="options"></Comp>
<p>
--->{{optSelected}}
</p>
</template>
`
I tried changin the 'input' event and 'change' event. not sure what im doing wrong.
i've found a solution that requires a vue-select library that i prefer not to use.
It's a simple detail: in vue 3, you need to use update:modelValue in order to change the v-model in parent component. (Reference: https://v3-migration.vuejs.org/breaking-changes/v-model.html)
And another thing: you souldn't use the prop as a v-model to prevent side effects in your application. You can read more about it here: https://eslint.vuejs.org/rules/no-mutating-props.html
Hope it helps:
<script>
export default {
props: {
options: {
type: Array
},
modelValue: undefined
},
emits: ['update:modelValue'],
watch: {
innerValue(newValue) {
this.$emit('update:modelValue', newValue)
},
modelValue(newValue) {
this.innerValue = newValue;
}
},
data() {
return {
innerValue: this.modelValue
};
}
};
</script>
<template>
<div>
<h1>Hi, I'm a component</h1>
<select v-model="innerValue">
<option v-for="option in options" :key="option">
{{ option }}
</option>
</select>
</div>
</template>
[Edit] Using Fallthrough Attribute:
You can use the v-bind="$atrrs":
<script>
export default {
props: {
options: {
type: Array
},
},
};
</script>
<template>
<div>
<h1>Hi, I'm a component</h1>
<select v-bind="$attrs">
<option v-for="option in options" :key="option">
{{ option }}
</option>
</select>
</div>
</template>
Read more: https://vuejs.org/guide/components/attrs.html#attribute-inheritance-on-multiple-root-nodes
After doing some digging, it seems that from child to parent you should update data by emitting events (not by v-model). This is my attempt of doing that (to no avail).
App.vue
<template>
<div>
<HelloWorld :count="count" #update:count="count= $event" />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
data() {
return {
count: 10
};
},
components: {
HelloWorld
}
};
</script>
HelloWorld.vue
<template>
<div class="hello">
<input
type="number"
min="0"
:value="count"
#input="$emit('input', $event.target.value)"
style="width:6em"
/>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
count: Number
}
};
</script>
Where am I going wrong? Ideally, I would like that changes in the input field of the child component would change the deposit field of the parent. Thanks!
I think that doesn't work because you're missing emits: ['update:count'] option in child component, But I recommend to name the prop as modelValue in child component and use v-model directive in parent instead of #update:count event :
<template>
<div>
<HelloWorld v-model="count" />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld.vue";
export default {
name: "App",
data() {
return {
count: 10
};
},
components: {
HelloWorld
}
};
</script>
HelloWorld.vue :
<template>
<div class="hello">
<input
type="number"
min="0"
:value="count"
#input="$emit('update:modelValue', $event.target.value)"
style="width:6em"
/>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
modelValue: Number
},
emits: ['update:modelValue'],
};
</script>
This allows you to create a custom input
Parent component has the method "startMethods" which just also has some other method "onDecrementStart ". OnDecrementStart method just only call Alert.
Under this line, added a code example but that code didn't work.
<template>
<div class="parent">
<div class="main">
<img alt="Vue logo" src="../assets/logo.png">
<SettingsBoard :max="maxValue" :start="startValue"
:startInc="startMethods"
/>
</div>
</div>
</template>
<script>
import SettingsBoard from "#/components/SettingsBoard";
export default {
name: "Main",
components: {
SettingsBoard
},
methods: {
startMethods: {
onDecrementStart () {
alert('Decrement')
},
onIncrementStart () {
alert('Incriment')
}
},
}
}
</script>
SettingsBoard component
<template>
<div class="container">
<label>
<button :#click="startInc.onDecrementStart()">-</button>
</label>
</div>
</template>
<script>
export default {
name: "SettingsBoard",
props: {
startInc: Object
},
}
</script>
I want to get like that if it's possible.
<template>
<div class="container">
<label>
<button :#click="startInc.onDecrementStart()">-</button>
<button :#click="startInc.onIncrementtStart()">+</button>
</label>
</div>
</template>
<script>
export default {
name: "SettingsBoard",
props: {
startInc: Object
},
}
</script>
To run a method in the parent component you should emit a custom event which has the parent method as handler :
<label>
<button #click="$emit('decrement')">-</button>
<button #click="$emit('increment')">+</button>
</label>
in parent component :
<div>
<SettingsBoard
#decrement="onDecrementStart"
#increment="onIncrementStart"
/>
...
methods: {
onDecrementStart() {
this.count--;
},
onIncrementStart() {
this.count++;
},
},
LIVE EXAMPLE
I'm trying to create a custom selector that I ill reuse several times and I want to set a prop to the function it has to trigger when a selection is made. Here is my code (only the relevant parts of it):
Main Selector:
<template>
<div>
<select name="selector" >
<option :key="option" v-for="option in options" #change="selection"> {{option}} </option>
</select>
</div>
</template>
<script>
export default {
name: 'CoffeeSelector',
props: {
options: Array,
selection: Function
},
}
</script>
The page where I use it:
<template>
<div>
<custom-selector :options='types' :selection="coucou"> </custom-selector>
</div>
</template>
<script>
import CustomSelector from './CustomSelector.vue'
export default {
name: 'Selectors',
components: {
CustomSelector
},
methods: {
coucou(){
console.log("coucou")
}
}
}
</script>
When I do this, nothing happens when I change the selection. Any ideas on why it happens? Thanks in advance
You can emit events to the parent component.
<template>
<div>
<select name="selector" >
<option :key="option" v-for="option in options" #change="onOptionChange(option)"> {{option}} </option>
</select>
</div>
</template>
<script>
export default {
name: 'CoffeeSelector',
props: {
options: Array
},
methods: {
onOptionChange(option) {
this.$emit('selection', option);
}
}
}
</script>
Then you can listen to those events within the parent component.
<template>
<div>
<custom-selector :options='types' v-on:selection="coucou"> </custom-selector>
</div>
</template>
<script>
import CustomSelector from './CustomSelector.vue'
export default {
name: 'Selectors',
components: {
CustomSelector
},
methods: {
coucou(option){
console.log("coucou: " + option)
}
}
}
</script>
try moving your #change to the select tag instead
<select name="selector" #change="selection">
<option :key="option" v-for="option in options"> {{option}} </option>
</select>
I have a component who show a list of data and I want to filter this list with different filters who are in a child component
I managed to do it with "computed" but only when I put everything in the parent component.
Test.vue
<template>
<div>
<filtres />
<garage v-for="g in garages" v-bind:gar="g" :key="g.id" />
</div>
</template>
<script>
export default {
name: 'test',
components: {
simplecomposant,
garage,
filtres
},
data(){
return{
garages: [],
}
},
mounted(){
var self = this;
axios.get('FETCHAPI').then(function (response)
{
self.garages = response.data.datas;
});
},
}
</script>
Filtres.vue
<template>
<div>
<label><input type="radio" v-model="selectedCity" value="All" /> All</label>
<label><input type="radio" v-model="selectedCity" value="1" /> City 1</label>
<label><input type="radio" v-model="selectedCity" value="2" />City 2</label>
</div>
</template>
<script>
export default {
name : 'filtres',
data(){
return{
selectedCity : "All"
}
},
}
</script>
garage.vue
<template>
<li class="aeris-simple-li">{{gar.name}}</span></li>
</template>
<script>
export default {
name : 'garage',
props: {
gar: {
type: Object
}
},
}
</script>
I want that when I select a filter (all, city 1, ...) it filters the datas "garages" who are in the parent component.