Putting value in a props from child to parent in vue.js is Error - vue.js

Good day,
I'm trying to pass a value from child to parent using the props but I'm having an error that says,
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "search"
Here are my sample codes:
Parent component
<template>
<div>
<child :search="search" />
</div>
</template>
<script>
export default(){
data: ()=>({
search: ''
})
}
</script>
Child component
<template>
<div>
<input type="text" v-model="search" />
</div>
</template>
<script>
export default{
props: ['search']
watch:{
search(val){
this.$emit('search', val);
}
}
}
</script>
I hope somebody can help me.

You're binding v-model to search. So if you type into your input vue to mutates the property. And it's just a warning which says that the data will be lost on next update, because then the property will passed again and your last value will be overwritten.
You could do something like this:
Child:
<template>
<div>
<input type="text" v-model="search" />
</div>
</template>
<script>
export default{
mounted () {
this.searchForResult= this.search;
},
props: ['search'],
data() {
searchForResult: ''
},
watch:{
searchForResult(val){
this.$emit('search', val);
}
}
}
</script>
Parent:
<template>
<div>
<child :search="search" />
</div>
</template>
<script>
export default(){
data: ()=>({
search: ''
})
}
</script>
There is also the possibility to add a search method which you can call from parent.

Parent component
<template>
<div>
<div>received: {{childResult}}
<child :search="search" #change="change" />
</div>
</template>
<script>
export default(){
data(){
return {
search: 'some content',
childResult: ''
}
},
methods:{
change(data){
this.childResult = data;
}
}
}
</script>
Child component
<template>
<div>
<input type="text" v-model="result" />
</div>
</template>
<script>
export default{
props: {
search: String
},
data(){
return {
result: this.search
};
},
watch:{
result(val){
this.$emit('change', val);
}
}
}
</script>

Related

Vue v-model bind to Parent component input element doesn't work

I am using Vue, Nuxt, Vue Good Table to live search a table. I create a child component named child.vue, and imported it into the parent page parent.vue. I used v-model to bind the searchTerm on the input element in the parent component. When I run it, live search doesn't work. And I got an warning from the console. Property or method "searchTerm" is not defined on the instance but referenced during render. Could you please help me out? I am new to Vue.js. Thank you
For the child.vue
<template>
<vue-good-table
:columns="columns"
:rows="rows"
:search-options="{
enabled: true,
externalQuery: searchTerm
}"
:sort-options="{
enabled: false,
}"
:group-options="{
enabled: true,
}"
/>
</template>
<script>
export default {
name: 'my-component',
data() {
return {
searchTerm: '',
columns: [xxxx]
}
}
}
</script>
For the parent.vue
<template>
<div>
<input type="text" placeholder="Live Search" v-model="searchTerm" />
</div>
<div>
<child />
</div>
</template>
Pass the prop from the parent to the child, and define searchTerm in the parents data
<template>
...
<input type="text" placeholder="Live Search" v-model="searchTerm" />
<child :searchTerm="searchTerm" />
...
</template>
<script>
data(){
return {
searchTerm: ''
}
}
...
</script>
Define the prop in the child, and remove searchTerm in the childs data
<script>
export default {
...
props: ['searchTerm'],
...
data(){
return {
//searchTerm: '' <- remove this from child
}
}
...
}
</script>
You can now access searchTerm in the childs <template> or this.$props.searchTerm in the childs <script>

Vuejs change component element value dynamicaly

I have a component in common between two other components A,B. This shared Comp has a button and its name changes depending on the component i use. How do I set the name dynamic?
I thought v-model solved the problem
What am I missing?
App.vue:
<test-a></test-a>
<test-b></test-b>
sharedComp.vue:
<template>
<div>
{{ btnValue }}
<input type="button" v-model="btnValue" />
</div>
</template>
<script>
export default {
data() {
return {
btnValue: "",
};
},
};
</script>
CompA.vue
<template>
<div>
<shared-comp
v-for="(item, index) in 3"
:key="index"
:value="'A'"
></shared-comp>
</div>
</template>
<script>
import SharedComp from "./SharedComp.vue";
export default {
components: { SharedComp },
};
</script>
CompB.vue
<template>
<div>
<shared-comp :value="'B'"></shared-comp>
</div>
</template>
<script>
import SharedComp from "./SharedComp.vue";
export default {
components: { SharedComp },
};
</script>
You have to define the properties you pass to your component inside of the 'sharedComp'.
Try something like:
<template>
<div>
{{ value }}
<input type="button" v-model="value" />
</div>
</template>
<script>
export default {
props: ['value'],
};
</script>
For further information on Props in Vue check the documentation page: https://v2.vuejs.org/v2/guide/components-props.html

Passing v-model to Child Component

I'm using Vue 3. In the example below I have 3 simple components, Name Component, Phone Component and Submit Component. How do I get in the respective properties of the Submit Component, what was entered in the inputs?
Name Component:
<template>
<div>
<input type="text" v-bind="name">
</div>
</template>
Phone Component:
<template>
<div>
<input type="text" v-bind="phone">
</div>
</template>
Submit Component:
<template>
<name></name>
<phone></phone>
</template>
<script>
export default {
data() {
return {
name: '',
phone: '',
}
}
}
</script>
<template>
<section>
<childComponent ref="nameOfRef" />
</section>
</template>
methods: {
submit() {
let Data = this.$refs.nameOfRef.$data; // nameOfRef.data or nameOfRef.$data or nameOfRef.phone or nameOfRef.name
}
},
Check I think it will help to catch your parent component data.

How to change parent data from a child component?

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

Vue: How do you bind a value to an input through a wrapper component?

I know you can use v-model to bind a value to an input in the same component. How do you create a wrapper component for an input and bind a value to it?
Login.vue
<template>
<div id="Login">
<Input v-bind:value="email"/>
<Input v-bind:value="password"/>
</div>
</template>
<script>
import Input from './Input.vue'
import Button from './Button'
export default {
name: 'Login',
components: {
Input,
Button,
},
data: () => ({
email:'test',
password:'test',
}),
methods: {
login: () => { debugger; }, //this.email and this.password are still set to test
}
}
</script>
Input.vue
<template>
<div class="input>
<input v-model="value"/>
</div>
</template>
<script>
export default {
name: 'Input',
props: {
value: String,
},
}
</script>
Current set up results in
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
Is the only way to do this by emitting an event?
If I got it correctly, you can try to create transparent wrapper (in my case AppInput)
SomeParent.vue
<div>
<AppInput v-model="parentModel" />
</div>
AppInput.vue
<template>
<input
class="app-input"
v-bind="$attrs"
:value="value"
v-on="{
...$listeners,
input: event => $emit('input', event.target.value)
}">
</template>
<script>
export default {
name: "AppInput",
inheritAttrs: false,
props: ["value"]
};
</script>
one of articles
The best way is use v-model for wrapper and on/emit for input
<div id="Login">
<Input v-model="email"/>
<Input v-model="password"/>
</div>
...
<div class="input>
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</div>
You can implement v-model directly in the input component by doing so.
<template>
<div class="input>
<input :value="value" #input="$emit('input', $event.target.value)"/>
</div>
</template>
<script>
export default {
name: 'Input',
props: ["value"]
}
</script>
And then use it in your parent component like this:
<template>
<div id="Login">
<Input v-model="email"/>
<Input v-model="password"/>
</div>
</template>
<script>
import Input from './Input.vue'
import Button from './Button'
export default {
name: 'Login',
components: {
Input,
Button,
},
data: () => ({
email:'test',
password:'test',
}),
methods: {
login: () => { debugger; }, //this.email and this.password are still set to test
}
}
</script>
See here