I'm using v-model in custom component, but when I try to get the data(value props) of the child component in the parent component, then I get the old value, although the data in the parent has changed. If I get the data of the child component through setTimeout, then I get the data I need. How do I synchronize the v-model #input event and the data I receive from the child element in the parent?
This is the logic: there are AppForm(parent) component and AppSelect(child) component. I'm binding v-model on AddSelect, and I follow the changes through watch() { v-model-data }. Then v-model data has changed I call AppForm.data() method, which iterates through the list of children and gets the value prop of AppSelect component, but this value is old.
Short example:
https://codesandbox.io/s/serene-wildflower-5seqx?file=/src/App.vue
You're trying to get the child component's prop inside a watcher watching the data property that the prop is bounded to. Of course, the watcher triggers first, then the data is passed onto the child component and the prop is updated. Its not a good design if you are relying on the order that Vue events and functions are fired, but if you must, you can use vm.$nextTick() function to get values after everything is synced.
watch: {
selectData(newV, oldV) {
alert("Select data from parent component: " + newV);
this.$refs.form.data();
this.$nextTick(() => {
alert("Show select data after 2sec");
this.$refs.form.data();
}, 2000);
},
},
Although, I'd suggest you shift the watcher inside the child component and access the data prop there.
Related
I'm struggling with this concept in vue.js..
I'm assuming that a component in Vue is an entity with some (html) representation and internal data or state. The component can then change it's internal data based on user's interaction with the template and inform the 'outer world' about its internal changes via events.
But then to put the component in context of the application as a whole most components need to receive data from the 'outer world' which would be done via props. So for a component to be useful it most often needs to change not only it's internal state but also some data it was given from the outer context - but props cannot be mutated directly. The internal data is for the internal working of the component but the real purpose of a component is to transform the data in props.
Lets say we have a component which is, via props, given an object representing a user profile for instance. The role of the component is to let the user edit their profile.
- to avoid mutating the prop (or a subproperties of the prop), i'd add a local copy of the prop which the component could work with freely - but i'd also have to add a watch to update the local copy every time the prop gets updated by the parent via v-bind.
</template>
<input v-model="localUserProfile.name"/>
</template>
<script>
export default {
props: {
userProfile: {
type: Object,
required: true
}
},
data: function () {
return {
localUserProfile: this.userProfile
}
},
watch: {
userProfile (newVal) { this.localUserProfile = newVal }
}
}
</script>
I could replace the watch with a computed property based on the given prop and let the component work over the computed property but then where to assign the edited values? Use the computed property's setter and 'emit' on changes?
Both these cases seem like a lot of extra code for a very common and repetitive task. What are some other common approaches to this? Are any of my assumptions wrong?
You should not update the prop from the children component :
All props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand.
In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should not attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.
You can read more about it here
If you have no other solution than updating if from the children component, it might be worth thinking about a different data flow strategy or design. (Components Basics)
I would like to know which is better way to emit data to parent in vue component. From parent to child I pass prop object but from child to parent with $emit. Should I pass object or value? e.g.: { product } or product.id and also I have to reuse some data in the { product } like product.price on event listener. What should I use? Emit an object or just value then loop and condition in listener function?
Just use a two way sync here:
#product.sync="product"
In the child:
this.$emit('update:product', product)
Whenever you make a change to the property of the product.
This does not work in case of Pass by reference. I mean it works but Vue is screaming don't mutate props directly...
Where movie is an object and genres is an array. Child components props and event
props: {
genres: {
type: Array,
default () {
return []
}
}
}
...
this.$emit('changeGenreList', this.genres)
I had to make the local copy of this array with slice() and then I was emitting this copy.
I know we can pass data to child components via Props. But it is reactive in one-way data flow mode. If the value of the data is changed in Parent component, it also has effect (update) on props in Child component.
In my case, I don't want to get update on specific prop in Child component even if that data in the Parent component is changed. It is because Child component will only responsible to show the data. But the data in the Parent Component still has to be reactive in Parent Scope.
I've read some forum article that suggest to use like Json. I feel it is a little dirty way and the data in my case is just one string.
Is there anyways to achieve that kind of solution?
You could copy the reactive prop in the created hook of the child component. The copy would not be reactive e.g.
export default {
props: {
reactive: Object
},
data: () => ({
nonreactive: null
}),
created() {
this.nonreactive = Object.assign({}, this.reactive)
}
}
Note: the way you copy the reactive prop will depend on the data type, the way I've shown will work for objects.
Maybe u can check this one
VueJS render once into an element
use v-once on your child component
Use prop as data property in child component. please see the fiddle link:
link here
Vue.component('greeting', {
props: ['user'],
data:function(){
return {
newuser:this.user
}
},
template: '<h1>hi {{ newuser }}</h1>'
});
I have split up the components only for the reason the base or the parent component code is growing in size and for code organization. so split the components based on the sections of the parent component.
So the each child component are the each section of the same parent component. But my question how to access the child component objects from parent component? Because most of the examples i see are based on the click event from parent component to view the child component (like dialog) and the value is passed back to the parent html click event and captures the values using emitter and output parameter.
Whereas in my case there is no such click action to trigger the child component. So how to communicate the values from child component to parent component?
In parent component
onDocumentSelect( documentData: IDocument) {
console.log(documentData);
}
<app-document [showDocument] = 'displayDocument' (selectDocument)=onDocumentSelect($event)></app-document>
In Child component:
#Output() selectDocument: EventEmitter<e.IDocument>;
#Input() showDocument: boolean;
I am triggering emit in the function where the data for the DocumentSource is computed.
this.selectDocument.emit(this.DocumentSource.data);
here this.DocumentSource is the dataTable which has value in Child component, that needs to be accessed in parent component.
Apart from this I have similar data for another field of different type needs to be passed to parent component from child component.
I get the below error while page loads
TypeError: Cannot read property 'subscribe' of undefined
In the above code snippet, by changing the type to any solved the issue.
On child component:
#Output() public selectDocument: EventEmitter<any> = new EventEmitter<any>();
On parent component:
onDocumentSelect( documentData: any) {
console.log(documentData);
}
I have a parent component
<template><child></child></template> export { components: [ child] }
and child component
<template><!-- markup --></template> export { props ['id'] }
When I retrieve information from a resource after posting I want to be able to pass the received data from parent to the child property.
// parent function
then(response=>{// need to set child.id = response.data });
Now I tried setting the property value directly and got the warning
[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
And I can't use emit or broadcast because I'm using Vue 2.0, $broadcast is undefined and I can't $emit to children. What would be the best way to pass the data? This value only lasts for the parent and child and does not need to be preserved or persisted.