2

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;
    }
});

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks much @Bert. Indeed, I was vaguely aware that let and const were the New Thing, but hadn't looked into them yet because var was "working" for me.
@wwninja A lot of cases it doesn't matter; this just happens to be one where it does :) The fix was more involved before let was available (it involved creating a closure in each iteration of the loop).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.