Siegfried
Siegfried

Reputation: 90

Watched prop callback of a component inside a v-if statement is not called

I have a component, "cmptest", which have a watched property, "needWatch". This component is inside a v-if statement, but the watched function is not called when it is rendered.

As shown in the example, the "needWatch" prop is setted with "value" data property from "cmpcheck", what makes me expect that the watch callback should be fired here.

If I remove the v-if statement, the function is called as expected when the checkbox is clicked.

<div v-if="value===true"><!--remove-->
    <cmptest :need-watch="value"></cmptest>
</div><!--remove-->

Is this by design? What am I doing wrong here?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Vue Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="vue.js"></script>

    <script type="text/x-template" id="cmptesttemplate">
        <div>
            <p>needWatch: {{needWatch}}</p>
            <p>updateByWatch: {{updateByWatch}}</p>
        </div>
    </script>

    <script type="text/x-template" id="cmpchecktemplate">
        <div>
            <input id="checkBox" type="checkbox" value="1" v-on:click="setCheckboxValue()">
            <div v-if="value===true">
                <cmptest :need-watch="value"></cmptest>
            </div>
        </div>
    </script>

</head>
<body>
<div id="container">
    <cmpcheck></cmpcheck>
</div>
<script>

    var cmptest = Vue.component('cmptest', {
        template: '#cmptesttemplate',
        data: function() {
            return {
                updateByWatch: ''
            }
        },
        props: ['needWatch'],
        watch: {
            needWatch: function(v) {
                console.log('Watched!');
                this.updateByWatch = Math.random();
            }
        }
    });

    var cmpcheck = Vue.component('cmpcheck', {
        template: '#cmpchecktemplate',
        data: function() {
            return {
                value: 'Unitialized'
            };
        },
        methods: {
            setCheckboxValue: function() {
                console.log('SELECTED');
                var el = $(this.$el).children('#checkBox').is(':checked');
                this.value = el;
            }
        }
    });

    new Vue({
        el: '#container',
        components: {
            'cmptest': cmptest,
            'cmpcheck': cmpcheck
        }
    });
</script>
</body>
</html>

Upvotes: 1

Views: 1046

Answers (1)

Nicolas P.
Nicolas P.

Reputation: 601

Well, as long as value is Unitialized (thus, not true), <cmptest :need-watch="value"></cmptest> will never be rendered, so the watcher does not actually exist. Once setCheckboxValue is called, if value is true, the cmptest will be rendered and then the watcher initialized. But value is already true, so it's not triggered.

However, you can use:

watch: {
  needWatch: {
    immediate: true,
    handler(nv, ov) { ... }
  }
}

so that your watcher callback runs when needWatch is initiated.

Upvotes: 1

Related Questions