vuejs update parent data from child component
Two-way binding has been deprecated in Vue 2.0 in favor of using a more event-driven architecture. In general, a child should not mutate its props. Rather, it should $emit
events and let the parent respond to those events.
In your specific case, you could use a custom component with v-model
. This is a special syntax which allows for something close to two-way binding, but is actually a shorthand for the event-driven architecture described above. You can read about it here -> https://v2.vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events.
Here's a simple example:
Vue.component('child', {
template: '#child',
//The child has a prop named 'value'. v-model will automatically bind to this prop
props: ['value'],
methods: {
updateValue: function (value) {
this.$emit('input', value);
}
}
});
new Vue({
el: '#app',
data: {
parentValue: 'hello'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<p>Parent value: {{parentValue}}</p>
<child v-model="parentValue"></child>
</div>
<template id="child">
<input type="text" v-bind:value="value" v-on:input="updateValue($event.target.value)">
</template>
Vue.js update parent data with an input from a child component
You're almost there, you can see in the code you've provided that the child component event is being emitted but the value is empty. The problem is you're not updating myDescription
, if you change your :value
to v-model
then it will update, as v-model
uses two way binding.
Also, if you want to update the file description, you can just do:
file.description = description;
Vue.component('myComponent', {
props: ["file"],
data() {
return {
myDescription: '',
}
},
mounted() {
this.myDescription = this.file.description;
},
template: `
<div>
<label>{{ file.name }}</label>
<br>
<input type="text" @input="update" v-model="myDescription"></input>
<br><br>
</div>
`,
methods: {
update() {
this.$emit("update-description", this.myDescription, this.file);
},
}
})
var app = new Vue({
el: '#app',
methods: {
updateDescription(description, file) {
console.log(description);
file.description = description;
}
},
data: {
files: [{
id: 1,
name: "Hello",
description: "",
},
{
id: 2,
name: "World",
description: "Foo",
},
{
id: 3,
name: "John",
description: "Bar",
}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div> {{ files }} </div>
<br>
<my-component v-for="file in files" :key="file.id" :file="file" @update-description="updateDescription" />
</div>
Vue 3: Unable to update parent data from child component checkbox
There's a couple of problems here:
$event.target.value
is a string rather than a boolean. Change this to$event.target.checked
- Your parent is listening to
input
but your child is emittingupdate:modelValue
. Save yourself a lot of hassle and usev-model
in the parent:
<CheckboxComponent
v-model="profile.doYouAgree"
label="Do you agree?"
/>
Update Parent Data from Child Modal Data using Props in vue
You emit event and pass data this.$emit('updated', this.client)
In parent component you listen to event from child and trigger method @updated="handleUpdate"
Take a look at following snippet pls:
Vue.component('client-add-form', {
template: `
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">Add/Modify Customer Information</p>
</header>
<section class="modal-card-body">
<b-field label="Name">
<b-input type="text" v-model="client.name" placeholder="Name"> </b-input>
</b-field>
<b-field label="Phone">
<b-input type="phone" v-model="client.phone" placeholder="Phone"> </b-input>
</b-field>
<b-field label="Email">
<b-input type="email" v-model="client.email" placeholder="Email"> </b-input>
</b-field>
<b-field label="Address">
<b-input type="textarea" v-model="client.address" placeholder="Address">
</b-input>
</b-field>
<b-field label="City">
<b-input type="text" v-model="client.city" placeholder="City"> </b-input>
</b-field>
<b-field label="Country">
<b-input type="text" v-model="client.country" placeholder="Country"> </b-input>
</b-field>
</section>
<footer class="modal-card-foot">
<b-button label="Close" @click="$parent.close()" />
<b-button label="Save" type="is-primary" @click="update" />
</footer>
</div>
`,
props: ["formData"],
data() {
return {
client: {...this.formData}
}
},
methods: {
update(){
//Database Operations etc
this.$emit('updated', this.client)
this.$parent.close()
}
},
})
new Vue({
el: '#demo',
data() {
return {
isComponentModalActive: false,
form: {
clientData: {
name: "Gaurav Kumar",
email: "imthegrv@gmail.com",
phone: "",
address: "",
city: "",
country: "",
taxCode: "",
Type: "",
},
}
}
},
methods: {
handleUpdate(client) {
this.form.clientData = client
}
}
})
<link rel="stylesheet" href="https://unpkg.com/buefy/dist/buefy.min.css">
<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/buefy/dist/buefy.min.js"></script>
<script src="https://unpkg.com/buefy/dist/components/table"></script>
<script src="https://unpkg.com/buefy/dist/components/input"></script>
<div id="demo">
<button @click="isComponentModalActive = true">
Add New Client
</button>
<b-modal
v-model="isComponentModalActive"
has-modal-card
full-screen
:can-cancel="false"
>
<client-add-form
:form-data="form.clientData"
@updated="handleUpdate"
></client-add-form>
</b-modal>
{{ form }}
</div>
How to change parent data from a child component?
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
how to edit the data value of the parent component from the child component in vue js
The solution is to use event emitting (Youtube Tutorial) to send updated data up to the parent component from the child component.
so the code becomes like this:
the parent component:
<template>
<div>
<button @click="show?show = false:show = true">
{{show?"Hide":"Show"}}
</button>
<item :show="show" @state="update($event)" />
</div>
</template>
<script>
import item from "item.vue"
export default {
components: {
item
},
data() {
return {
show: null,
};
},
methods: {
update(value) {
this.show = value;
}
}
};
</script>
the child component:
<template>
<div @click="action" v-if="show">
Vue Js - click here to Hide
</div>
</template>
<script>
export default {
props: {
show: Boolean,
},
methods: {
state() {
if (this.show) {
return false;
} else {
return true;
}
},
action() {
this.$emit("state", this.state())
}
}
};
</script>
Thank you @D.Schaller for helping
Update parent model from child component Vue
You can use custom events to send the data back.
To work with custom events, your data should be in the parent component, and pass down to children as props:
<step1 :someValue="value" />
and now you want to receive updated data from child, so add an event to it:
<step1 :someValue="value" @update="onStep1Update" />
your child components will emit the event and pass data as arguments:
this.$emit('update', newData)
the parent component:
methods: {
onStep1Update (newData) {
this.value = newData
}
}
Here is a simple example with custom events:
http://codepen.io/CodinCat/pen/QdKKBa?editors=1010
And if all the step1, step2 and step3 contain tons of fields and data, you can just encapsulate these data in child components (if the parent component doesn't care about these row data).
So each child has its own data and bind with <input />
<input v-model="data1" />
<input v-model="data2" />
But the same, you will send the result data back via events.
const result = this.data1 * 10 + this.data2 * 5
this.$emit('update', result)
(again, if your application becomes more and more complex, vuex will be the solution.
How to update the child component b-tabs value from parent component in vuejs
The error you're facing happens when you're trying to mutate the value of a prop
, because prop
values are coming from parents. If the parent changes it, your change inside the child will be overwritten.
Thus, when a child needs to change a prop
, it has to emit an event to the parent, update the parent value which, in turn flows the change back into the child, via the prop.
Props down, events up!
To eliminate part of the boilerplate for this mechanism, Vue 2 provided the .sync
modifier.
In Vue3, .sync
was deprecated and removed (breaking change)!someProp.sync
has been replaced by v-model:someProp
, because:
- they were providing the same functionality (dual binding),
- this increased the confusion between the two syntaxes and their particular implementation details.
- now
v-model
behaviour is aligned across native form elements and Vue components.
Vue's author (Evan You), has declared over the past years that, going forward, the core team's intention is to reduce the API surface, by removing unnecessary or confusing syntax options.
Vue 2 example:
Vue.component('tab', {
template: `#tab-tpl`,
props: ['index', 'text'],
computed: {
tIndex: {
get() { return this.index },
set(val) { this.$emit('update:index', val); }
}
}
})
new Vue({
el: '#app',
data: () => ({
tabs: [{text: 'one'}, {text: 'two'}, {text: 'three'}],
tabIndex: 0
}),
computed: {
currentIndex: {
get() { return this.tabIndex },
set(val) {
this.tabIndex = (this.tabs.length + val) % this.tabs.length;
}
}
}
})
.tab-pills {
display: flex;
border-bottom: 1px solid #ccc;
cursor: pointer;
}
.active {
color: red;
}
.tab-pills > div { padding: .3rem .7rem; }
.tab-content { padding: 1rem .7rem; }
.tab-body { padding: 1rem 0 }
<script src="https://v2.vuejs.org/js/vue.min.js"></script>
<div id="app">
<div class="tab-pills">
<div v-for="(tab, key) in tabs"
v-text="tab.text"
:class="{ active: key === currentIndex }"
:key="key"
@click="currentIndex = key">
</div>
</div>
<tab :index.sync="currentIndex" :text="tabs[currentIndex].text" class="tab-content"></tab>
</div>
<template id="tab-tpl">
<div>
<div v-text="text" class="tab-body"></div>
<button @click="tIndex -= 1">Prev</button>
<button @click="tIndex += 1">Next</button>
</div>
</template>
(VueJS) Update parent data from child component
There isn't the relation that you said between the two components.
The component that you called parent
is in reality the child... and the child is parent
.
The parent component is always the one that calls the other, in your case:
//Parent component
<template>
...
<msm-select :options="policies" :model="isShowingUpdate" /> << the child
...
</template>
You should change the props/events between the two components.
Edit:
You can edit the:
onChange(value) {
if (this.selected !== value) {
this.flagValue = true;
} else {
this.flagValue = false;
}
}
To a new one like the following:
On the children:
onChange(value) {
if (this.selected !== value) {
this.flagValue = true;
} else {
this.flagValue = false;
}
this.$emit('flagChanged', this.flagValue)
}
On the parent use the emit
event to capture and call some other method:
//HTML part:
<msm-select :options="payments" :model="isShowingUpdate" v-on:flagChanged="actionFlagChanged" />
//JS part:
methods: {
actionFlagChanged () {
//what you want
}
}
Can I give you some tips
?
It's not a (very) good name of a function the one called:
onChange
inside a onChange event... try something like: updateFlag (more
semantic).I think that you can delete the watch part and do it in the onChange
eventTry to find a good documentation/tutorial (i.e the official documentation) to learn more about parent/child communication.
Remember to add the event-bus import:
import { EventBus } from './event-bus'
Hope it helps!
Related Topics
How to Edit a JavaScript Alert Box Title
Facebook Social Plug-In Not Showing Up When Added Dynamically
How to Add New Array Elements at the Beginning of an Array in JavaScript
How to Get a JavaScript Object's Class
How to Use Namespaces with Typescript External Modules
How to Display Length of Filtered Ng-Repeat Data
How to Get the Size of a JavaScript Object
How to Check If Dst (Daylight Saving Time) Is in Effect, and If So, the Offset
How to Get Character Array from a String
Node.Js Plans to Support Import/Export Es6 (Ecmascript 2015) Modules
What Is the Purpose of a Plus Symbol Before a Variable
Convert Base64 String to Arraybuffer
How to Read the Client's MAChine/Computer Name from the Browser
How to Get Node Datum on Mouseover in D3 V6
Do Common JavaScript Implementations Use String Interning
Why Doesn't My Equality Comparison Using = (A Single Equals) Work Correctly