How to use a Vue.js watcher?

Sometimes you want to perform an action when a value has changed. A Vue.js watcher is the thing you need in that case.


Basic example of a Vue.js watcher

Let's begin with an example showing basic usage of a watcher.

<template>
	<p>Items in cart: {{ items }}</p>

	<button @click="addToCart">Add</button>
</template>

<script>
export default {
    data() {
        return {
            items: 0 // Number of items in cart
        }
    },
    methods: {
        addToCart: function() { // Method for adding item to cart
            this.items += 1 // Add one item
        }
    },
    watch: { // Here we define the watchers
        items: function() { // We add a watcher to the "items" variable, this will be called when items changes
            console.log('Number of items in cart: ' + this.items) // Log the output to the browser's console
        }
    }
}
</script>

What did we do?
In the template we basically just added a paragraph that prints out the value of the "items" variable. Underneath the paragraph we've added a button which calls the "addToCart" function when it's clicked.

Getting the old value

Sometimes it might be useful to know what the value was before it was changed. We can get this value by adding two parameters to the watch-function.

<template>
	<p>Items in cart: {{ items }}</p>

	<button @click="addToCart">Add</button>
</template>

<script>
export default {
    data() {
        return {
            items: 0 // Number of items in cart
        }
    },
    methods: {
        addToCart: function() { // Method for adding item to cart
            this.items += 1 // Add one item
        }
    },
    watch: { // Here we define the watchers
        items: function(newVal, oldVal) { // We add a watcher to the "items" variable, this will be called when items changes
            console.log('New value: ' + newVal)
            console.log('Old value: ' + oldVal)
        }
    }
}
</script>

A more useful example

A cool thing we can use a watcher for, is to create a search that will only be called when it's 500 ms since last time a key was pressed.

<div id="app">
    <h1>Search</h1>

    <input type="text" v-model="query">

    <p>{{ result }}</p>
</div>

<!-- Include Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<!-- Include lodash (A modern JavaScript utility library delivering modularity, performance & extras.) -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<!-- Our script -->
<script>
new Vue({
    el: '#app',
    data: function() {
        return {
            query: '',
            result: 'Write a search term'
        }
    },
    watch: {
        query: function() {
            // When we start typing we show this message as the temporary search result
            this.result = 'We will start searching when you stop typing!'

            // Call the debouncedPerformSearch function (debounce will make sure that it is not called
            // before after 500ms after the last key is clicked)
            this.debouncedPerformSearch()
        }
    },
    created: function() {
        // _.debounce is a function which comes from the lodash script we included.
        // It's created to that we can limit how often a function is called.
        // You don't want your site to perform a heavy operation like a search
        // everytime a key is clicked. This function makes it possible to only
        // perform the search 500 milliseconds after the last key is clicked.

        // When our Vue instance is created, we set that debouncedPerformSearch is a function
        // that calls the debounce function, which again calls the performSearch function after 500 ms
        this.debouncedPerformSearch = _.debounce(this.performSearch, 500)
    },
    methods: {
        performSearch: function() {
            if (this.query) { // Check if query is set
                this.result = 'Searching...' // Set the result text to Searching... while we wait for the "server"
            }

            // You will usually call a API or something here...

            // This is just for demo purpose, reset the result text after 2000 milliseconds
            setTimeout(() => {
                this.result = 'Start typing...'
            }, 2000);
        }
    }
})
</script>

Summary

As you can see with these examples, a watcher can be very helpful. But be careful, don't make changes to the variable you are watching. Doing so will make the browser crash.