Search code examples
javascriptvue.jsvuejs2

Property or method "value" is not defined on the instance in vue js 2 nested component


I wrote a basic vue js 2 basic example to test nested components.

Below is components and template structure.

    Vue.component('form-com', {
        template: '#form',
        props: ['value'],
        methods: {
            onInput: function (event) {
                this.$emit('input', event.target.value);
            }
        }
    });

    Vue.component('message-com', {
        template: '#message',
        data: function () {
            return {
                msg: 'Hello'
            }
        },
        props: ['user']
    });

    Vue.component('welcome-com', {
        template: '#welcome',
        data: function () {
            return {
                user: 'ahmad'
            }
        }
    });

    new Vue({
        el: '#container'
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>

<!--Form Template-->
<template id="form">
    <div>
        <div class="form-control">
            <label>Enter Your Name:</label>
            <input type="text" v-bind:value="value" :input="onInput">
        </div>
    </div>
</template>

<!--Hello Message Template-->
<template id="message">
    <div>
        <h3>{{msg}} {{user}}</h3>
    </div>
</template>

<template id="welcome">
    <div>
        <form-com :value="value"></form-com>
        <br>
        <message-com :user="user"></message-com>
    </div>
</template>

<div id="container">
    <welcome-com></welcome-com>
</div>

But when run app in browser this error is shown:

[Vue warn]: Property or method "value" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.

found in

---> <WelcomeCom>
       <Root>

what is problem?

Update:

I just Rewrite this Fiddle from one of chapters of Learning Vue.js 2. I just rename some parameters and component and templates names. but when I copy main fiddle to my code all things worked.


Solution

  • In your form-com component you can set up a v-model which binds the input value and set up a watcher to observer the changes in the input which in turn emits an custom-event which tells the parent component that a change has taken place.

    Vue.component('form-com', {
            template: '#form',
            data(){
                return{
                    myInput:''
                }
            },
            watch: {
                myInput: function (inputVal) {
                    this.$emit('input', inputVal);
                }
            }
        });
    
        Vue.component('message-com', {
            template: '#message',
            data: function () {
                return {
                    msg: 'Hello'
                }
            },
            props: ['user']
        });
    
        Vue.component('welcome-com', {
            template: '#welcome',
            data: function () {
                return {
                    user: 'ahmad'
                }
            },
            methods:{
                updateUser(value){
                    this.user = value;
                }
            }
        });
    
        new Vue({
            el: '#container'
        })
    

    You can listen to the events emitted from the child **form-com ** component using v-on:input or shorthand @input directly in the parent template (welcome component) where the child component is used.

    HTML

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
    
    <!--Form Template-->
    <template id="form">
        <div>
            <div class="form-control">
                <label>Enter Your Name:</label>
                <input type="text" v-model="myInput">
            </div>
        </div>
    </template>
    
    <!--Hello Message Template-->
    <template id="message">
        <div>
            <h3>{{msg}} {{user}}</h3>
        </div>
    </template>
    
    <template id="welcome">
        <div>
            <form-com @input="updateUser($event)" ></form-com>
            <br>
            <message-com :user="user"></message-com>
        </div>
    </template>
    
    <div id="container">
        <welcome-com></welcome-com>
    </div> 
    

    Here is the jsFiddle

    If you don't want to use a watcher then you can do it using computed setter . Have a look at the fiddle which is using a computed-setter