You can watch the props by using a watcher function in your parent (Form.vue) component inside the mounted hook.
You have to just attach a ref to your top most child component. For ex :
<order-form-info :name="name" :phone="phone" ref="orderFormComponent"></order-form-info>
Live Demo :
Vue.component('orderFormInfo', {
props: ['name', 'phone'],
template: `<div>
<input-field
placeholder="phone number"
type="text"
v-model="phone"/>
<input-field
placeholder="recipient name"
type="text"
v-model="name"/>
</div>`
});
Vue.component('inputField', {
props: ['value', 'placeholder'],
template: `<input
:value="value"
@input="$emit('input', $event.target.value)"
:placeholder="placeholder"
/>`
});
var app = new Vue({
el: '#form',
data: {
name: 'Alpha',
phone: '1111111111'
},
mounted() {
this.$watch(
"$refs.orderFormComponent.phone", (newVal, oldVal) => {
console.log(newVal, oldVal)
}
);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="form">
<order-form-info :name="name" :phone="phone" ref="orderFormComponent"></order-form-info>
</div>
Answer from Rohìt Jíndal on Stack OverflowYou can watch the props by using a watcher function in your parent (Form.vue) component inside the mounted hook.
You have to just attach a ref to your top most child component. For ex :
<order-form-info :name="name" :phone="phone" ref="orderFormComponent"></order-form-info>
Live Demo :
Vue.component('orderFormInfo', {
props: ['name', 'phone'],
template: `<div>
<input-field
placeholder="phone number"
type="text"
v-model="phone"/>
<input-field
placeholder="recipient name"
type="text"
v-model="name"/>
</div>`
});
Vue.component('inputField', {
props: ['value', 'placeholder'],
template: `<input
:value="value"
@input="$emit('input', $event.target.value)"
:placeholder="placeholder"
/>`
});
var app = new Vue({
el: '#form',
data: {
name: 'Alpha',
phone: '1111111111'
},
mounted() {
this.$watch(
"$refs.orderFormComponent.phone", (newVal, oldVal) => {
console.log(newVal, oldVal)
}
);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="form">
<order-form-info :name="name" :phone="phone" ref="orderFormComponent"></order-form-info>
</div>
I was able to solve it this way, I found an article on the Internet. Here are the changes:
OrderFormInfo.vue
<Input
placeholder="Phone number"
type="text"
:error-status="false"
:errors="[]"
:value="phone"
@input="$emit('input-phone', $event)"
/>
OrderForm.vue
<OrderFormInfo.
v-if="step === 'info'"
:name="name"
@input-name="name = $event"
:phone="phone"
@input-phone="phone = $event"
@next-step="handleNext"
/>
Videos
No difference in your specific example, but there is a very important difference between those two notations, specially when it comes to Vue.js: the this won't reflect the vue instance in arrow functions.
So if you ever have something like:
export default {
props: ['stuffProp'],
data: () => ({
myData: 'someData',
myStuff: this.stuffProp
})
}
It won't work as you expect. The this.stuffProp won't get the stuffProp prop's value (see below for more on the reason why).
Fix
Change the arrow function to, either (ES6/EcmaScript 2015 notation):
export default {
props: ['stuffProp'],
data() { // <== changed this line
return {
myData: 'someData',
myStuff: this.stuffProp
}
}
}
Or to (regular, ES5 and before, notation):
export default {
props: ['stuffProp'],
data: function() { // <== changed this line
return {
myData: 'someData',
myStuff: this.stuffProp
}
}
}
Reason
Don't use arrow functions (() => {}) when declaring Vue methods. They pick up the this from the current scope (possibly window), and will not reflect the Vue instance.
From the API Docs:
Note that you should not use an arrow function with the
dataproperty (e.g.data: () => { return { a: this.myProp }}). The reason is arrow functions bind the parent context, sothiswill not be the Vue instance as you expect andthis.myPropwill be undefined.
It has something to do with ES5 or ES6 syntax, If you have used arrow functions ()=> in your previous scripts it is safe to use the following codes.
// tested and this.myData can be accessed in the component
data: () => { return {
myData: 'someData',
myStuff: this.stuffProp
} }
// this also works
data: () => ({
myData: 'someData',
myStuff: this.stuffProp
})
It seems as though the comments on your question missed a key point when considering your specific code example.
In a root Vue instance i.e. constructed via new Vue({ ... }), you can simply use data: { ... } without any problems. The issue is when you have reusable components that are defined via Vue.component(...). In these instances, you need to either use data() {return { ... };} or data: function() {return { ... };}.
The reason for this is to ensure that for each individual instance of the reusable child component, there is a unique object containing all of the data being operated on. If, in a child component, you instead use data: { ... }, that same data object will be shared between the child components which can cause some nasty bugs.
Please review the corresponding section of the Vue.js documentation for more information regarding this problem.
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
so initiating a new vue instance dose not matter between data:{} as a object or data(){return{}} or data:function(){return{}}.
It matters when it comes to component lets try an example:
<body>
<div id="app">
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component('counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: {
counter:0
}
});
</script>
Output:
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
Now lets watch in vue object:
<body>
<div id="app">
<button v-on:click="counter += 1">{{ counter }}</button>
<button v-on:click="counter += 1">{{ counter }}</button>
</div>
<script>
new Vue({
el: '#app',
/*data() {
return {
counter:0
}
},*/
//or (output same)
/*data: function () {
return {
counter: 0
}
}*/
//or (output same)
data:{
counter:0
}
});
</script>
</body>
//Now let's try data as a function in the component to reuse same component over and over again.
<body>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component('counter', {
template: '<button v-on:click="counter += 1">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
}
})
new Vue({
el: '#app'
});
</script>
</body>