wwninja
wwninja

Reputation: 45

Setting vue.js watchers within for loop

Experimenting with adding watchers dynamically in Vue.js. Disconnect between desired/actual results is shown in the commented portion below. Occasional/amateur coder here; I suspect my problem is less with Vue and more with understanding of JavaScript fundamentals. Thanks in advance!

new Vue({
    el: '#app',
    data: {
        a: 1,
        b: 2,
        c: 3
    },
    methods: {
        setUpWatchers(array) {
            for (var i in array) {
                var key = array[i];

                this.$watch(key, function(newValue) {
                    console.log(key + ': ' + newValue);

                    //desired output is:
                    //  a: 4
                    //  b: 5
                    //  c: 6

                    //actual output is:
                    //  c: 4
                    //  c: 5
                    //  c: 6

                });
            }
        }
    },
    created() {
        this.setUpWatchers(['a', 'b', 'c']);

        this.a = 4;
        this.b = 5;
        this.c = 6;
    }
});

Upvotes: 2

Views: 1390

Answers (1)

Bert
Bert

Reputation: 82499

You're correct, this is a classic javascript "gotcha".

Variables declared with var have a function scope. When using var all of the functions declared in your loop (you are declaring 3; the handlers for $watch) are using the same variable, which, after the loop is complete, points to c.

A quick fix is to declare your variables with let. let has block scope, so each function declared in your loop will have access to just the copy of the variable as it existed at the time the function was created.

Here is a working example.

new Vue({
    el: '#app',
    data: {
        a: 1,
        b: 2,
        c: 3
    },
    methods: {
        setUpWatchers(array) {
            for (let i in array) {
                let key = array[i];

                this.$watch(key, function(newValue) {
                    console.log(key + ': ' + newValue);
                });
            }
        }
    },
    created() {
        this.setUpWatchers(['a', 'b', 'c']);

        this.a = 4;
        this.b = 5;
        this.c = 6;
    }
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app"></div>

Ideally, these days, you should be using let or const and almost never var. There are numerous resources that are available that will describe the differences.

Upvotes: 1

Related Questions