Understanding VueJs Computed properties and Watchers.
Tags: vue, javascript, computed, watcher
Published: 2020-05-16 17:22:34

---
title: Understanding VueJs Computed properties and Watchers. 
published: true
description: A example based explanation and use cases of computed properties and vue watchers.
tags: vuejs, javascript, computed, watcher
---
Vue.js is an open-source model–view–viewmodel front end JavaScript framework for building user interfaces and single-page applications. The most interesting point about Vue is that, it's super easy to learn. I've been playing around and doing some projects with Vue lately and thought it might be a good idea to share my experience.

With that being said, if you are pretty new to *Vue* then I would recommend you to visit the  [official documentation](https://vuejs.org/v2/guide/). But do remember to come back here :). 

In this blog post, we are going to take a deep dive into *VueJS's* *computed properties* and *watchers*. We will go beyond the traditional definition and try to build some real world things here. I will be using codepens for most of the examples, so feel free to check them out.

### So What is a computed property ?
A computed property is a kind of method that always returns a value. We can mainly use it to derive values from other properties. But that's not the real power of computed properties.

Computed properties are reactive in nature meaning when the values used inside of a computed property changes, it reacts to them and re-evaluates the properties again. Most importantly, computed properties are cached which means it can enhance performance while  dealing with complex loops.

So computed property is a function that always returns a value, huh ?. Yup!! It's a method which acts as property. If this sounds confusing, don't worry about it. Let's take a close look at it with an example.
```html
<div>
  <div v-if="commentsAvailable">
    comments are not available for this blog at this moment!
  </div>
  <div v-else>
    // Logic to display comments
  </div>
</div>
```

```javascript
new Vue({
  data() {
    return {
      comments: [],
    };
  },
  computed: {
    commentsAvailable() {
      return !_.isEmpty(this.comments);
    },
    totalCount() {
     return this.comments.length;
    }
  },
  methods: {
    async fetchComments() {
      try {
        this.comments = await CommentService.fetchComments();
      } catch (err) {
        this.comments = [];
      }
    },
  },
  created() {
    this.fetchComments();
  },
});
```
So initially we won't be seeing any comments here as the *commentsAvailable* evaluates itself to false. we can simply use this computed property to sort of display a loader when there are no comments and when comments are fetched, then the loader becomes hidden and comments are shown. 

The *commentsAvailable* computed can be accessed like a normal property  *this.commentsAvailable* inside a method and *commentsAvailable* inside template.

One other use case is to compute or derive values from the existing data property. Let's consider the following example, where we have a few cart items as a data property and *addToCart()* which basically adds an item to the cart items. But that is not the deal here, we are interested in the total price of purchase, i.e.*total* computed property, which calculates the total price of products added to the cart.

So when the *cartItems* changes(added/removed), the computed property gets reevaluated and we get updated purchase price.

```javascript
new Vue({
  data() {
    return {
      cartItems: [],
    };
  },
  computed: {
    total() {
      const totalAmount = this.cartItem.reduce(
        (acc, curr) => acc + curr.price * quantity,
        0
      );
      return totalAmount;
    },
  },
  methods: {
    addToCart(item) {
      this.cartItems.push(item);
    },
  },
});
```

### Computed property must be a synchronous operation!

A computed property must be a synchronous method, we simply can't have a method which perform any *async* operation like fetching results from DB or making an *http* request etc.

Let's take another example to understand this in a more better way. Please take a look at this following code, where we are simply displaying a few food items and the macros nutrients present in it.

Initially the table is meant to display only *protein* and *calories* for the food items. But when we check the *Show All Macro checkbox*, it displays all the macros for the food items.

```html
<div class="container-fluid">
  <div class="row align-items-center justify-content-center">
    <label>Show All Macros</label>
    <input
      type="checkbox"
      v-model="showDetailView"
      style="margin-left: 10px;"
    />
  </div>
  <div class="row">
    <div>
      <table id="table" class="table">
        <thead>
          <tr>
            <td v-for="h in tableHeaders" :key="h.value">{{h.text}}</td>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(row, index) in rows" :key="row.name">
            <td v-for="header in headers">
              {{ row[header.value] }}
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</div>
```

It's important to notice that the *tableHeaders* and *rows* are computed properties, not the normal data properties because they are reactive and when the *show all macros* prop changes, these are re-evaluated and populate the table accordingly.

```javascript
new Vue({
  el: "#app",
  computed: {
    tableHeaders() {
      if (!this.showDetailView) {
        return this.headers.filter((h) =>
          this.defaultHeaders.includes(h.value)
        );
      } else {
        return this.headers;
      }
    },
    rows() {
      if (this.showDetailView) {
        //console.log("should return all foods", this.foods);
        return this.foods;
      } else {
        let data = this.foods.map((f) => {
          let obj = {};
          this.defaultHeaders.forEach((key) => (obj[key] = f[key]));
          return obj;
        });
        console.log(" data :", data);
        return data;
      }
    },
  },
});
```
{% codepen https://codepen.io/sarojsasmal/pen/OJyOxGd %}

There may be times, when you need a way to track changes of certain properties and perform some operations in relation to that. *Watchers* are exactly meant for that purpose. 

Using watchers, we can watch for changes and perform operations. Unlike computed properties, the method we can use inside a watcher can perform both *sync* and *async* operations depending on the requirements.

One example of a using computed property and watcher in a single component would be in building a pagination control. 

Now let's consider the following code pen example which extends the previous code pen with pagination feature.

We have a couple of html controls here, first off the select box, which has v-model attached to it, and a watcher watches for changes and the grid reloads data with selected number of rows whenever it changes.

Then we have a few computed properties here as well, *pages* which calculates total number of pages based on the total number of rows selected from drop down. And finally the *totalItems*, *rangeStart* and *rangeEnd* as text which displays `showing 1-10 of 16` text.

I would encourage you to take a look at the following codepen and just play around with the pagination control  to get a sense of how the *rangeStart* and *rangeEnd* changes dynamically.
{% codepen https://codepen.io/sarojsasmal/pen/dyYgpRX %}

I hope this article has helped you give an insight into computed properties and watchers. If you have any questions, feel free to leave a comment . Till next time, stay safe, have fun and keep exploring..