Vue.js Basics Part 3 | Computed Property
Tags: webdev, vue, javascript, programming
Published: 2022-09-01 20:49:14

Today, I will be talking about computed property in Vue.js. First, I will code [this tutorial](https://vuejs.org/tutorial/#step-8) from vuejs.org. Afterwards, I will touch the differences between `methods` and `computed` properties in Vue.js (not in detail).

_This is part 3 of my Vue.js Basics series, to read part 2, please go to [here](https://dev.to/ahmetmeliksah/vuejs-basics-part-2-v-for-list-rendering-1fol)_

Here's the whole code: 
```javascript
<script>
let id = 0

export default {
  data() {
    return {
      newTodo: '',
      hideCompleted: false,
      todos: [
        { id: id++, text: 'Learn HTML', done: true },
        { id: id++, text: 'Learn JavaScript', done: true },
        { id: id++, text: 'Learn Vue', done: false }
      ]
    }
  },
  computed: {
    hideCompletedTodos() {
      return this.hideCompleted ? this.todos.filter(item => !item.done) : this.todos
    }
  },
  methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo, done: false })
      this.newTodo = ''
    },
    removeTodo(todo) {
      this.todos = this.todos.filter(item => item.id !== todo.id)
    },
    toggleHideCompleted() {
      this.hideCompleted = !this.hideCompleted
    }
  }
}
</script>

<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" />
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in hideCompletedTodos" :key="todo.id">
      <input type="checkbox" v-model="todo.done">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="toggleHideCompleted">
    {{ hideCompleted ? 'Show all' : 'Hide completed' }}
  </button>
</template>

<style>
.done {
  text-decoration: line-through;
}
</style>
```

Time to read to read code above in small chunks!

```javascript
export default {
  data() {
    return {
      newTodo: '',
      hideCompleted: false,
      todos: [
        { id: id++, text: 'Learn HTML', done: true },
        { id: id++, text: 'Learn JavaScript', done: true },
        { id: id++, text: 'Learn Vue', done: false }
      ]
    }
  },
```

In our `data(){}` property we've got `newTodo` for `text` key property in our `todos` array. `hideCompleted` key for hiding completed todos, this is a boolean value (true or false). Its task is to hide completed todos if it's true, and show all todos regardless of they're completed or not whhen it's false. Finally, we've got an array of objects that stores our todos. As you notice, we've got a new key (`done:`) in our objects. That's to alter styling for tasks those are done, later on that one.

Next, **computed** property:

```javascript
computed: {
    hideCompletedTodos() {
      return this.hideCompleted ? this.todos.filter(item => !item.done) : this.todos
    }
  },
```

`hideCompletedTodos()` function returns _something_ based on  `hideCompleted`'s boolean value (true or false). If `hideCompleted` is `true`, it filters `item`s those `item.done` properties are false. In other words, we will have only `item.done` with falsy values left because `item => !item.done` this code returns items those `item.done` values are falsy. `: this.todos` this code says, else (if hideCompleted is **not** `true`), then return `todos` array altogether.

A bit more about computed. At first glance, computed may look like as if it's the same with methods, but it's not. First of all, `computed` re-renders only the changed element, on the other hand, `methods` re-render everything. This becomes a performance issue. To solve this use `computed`, a `computed` property tracks reactive state as dependencies, and caches the result. Once when the dependencies change, it updates. However, methods property updates even if the result doesn't change.

Time to get back to our code

```javascript
methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo, done: false })
      this.newTodo = ''
    },
    removeTodo(todo) {
      this.todos = this.todos.filter(item => item.id !== todo.id)
    }
  }
}
```

`addTodo()` function adds (actually 'pushes') a new object to the `todos` array. Finally, it sets `this.newTodo` to an empty string, so we won't see [object Object] weird thing in the input once the form (we will talk about it soon) is submitted.

`removeTodo(todo)` function takes a parameter - todo. When 'X' button is clicked, it will bring that particular 'todo' ({ id: id++, text: 'Learn HTML', done: true }... one of these) and filter (remove) it. Since, I've given `item` parameter in _filter_ method, each to do will be represented as `item`. Logic behind this code; `this.todos.filter(item => item.id !== todo.id)`, this compares if `item.id` and `todo.id` are **not** the same. Then, it returns items those have different ids. 

What the heck does this mean? So, when we click on 'X' button, it returns an object with an id key. As you know `filter` method iterates over arrays. So, it iterates over `todos` array, and returns `item`s those ids don't match `todo.id` that comes from the _item_ parameter. <script></script> part of this code is done, not let's talk about the template part.

```javascript
<template>
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" />
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in hideCompletedTodos" :key="todo.id">
      <input type="checkbox" v-model="todo.done">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
    {{ hideCompleted ? 'Show all' : 'Hide completed' }}
  </button>
</template>
```
`@submit.prevent` prevents forms from refreshing pages when form is submitted. Then, we've got an input tag that is two-way-binded to newTodo data. v-model: is responsible for syncing `newTodo` data and `addTodo()` function. Outside of our form we have got a `list` tag.

Here's how v-for works in a list tag:
As you see there's `todo in hideCompletedTodos`. Yes, we've got todos array, but what is todo? It's a local variable that will be alive only in this <li> tag because it's created in it. That means, `todo` is not accesible outside of <li></li> in this case. So, we've got an array of objects, by using v-for, we iterate over objects in `hideCompletedTodos` array. So, `todo` represents each object in `hideCompletedTodos` array. Since `todo` is a local variable, we can name it however we wish, but understandable naming is one of the best practices. For instance, if I had an array of `books`, I would have coded it as `<li v-for="book in books" :key="book.id"> ... </li>`.

**quick reminder**
```javascript
hideCompletedTodos() {
      return this.hideCompleted ? this.todos.filter(item => !item.done) : this.todos
    }
```
The code above returns filtered `todos` array or `todos` array in its original form, that's why `<li v-for="todo in hideCompletedTodos" :key="todo.id">` v-for loop is like this. So, `hideCompletedTodos` is either filtered (based on objects `done` value property) `todos` array or untouched todos array.

`<input type="checkbox" v-model="todo.done">` to understand this part, I will share <style></style> part of the code.

```javascript
<style>
.done {
  text-decoration: line-through;
}
</style>
```
In short, the code above has a CSS class `.done` that outs line through text. This code `v-model="todo.done"` binds `todo`'s done property with `done` CSS class. So, when the checkbox has a tick in it, `.done` CSS class is added, and a line goes through the text.

How do we get specific `todo` from the list by `removeTodo(todo)`? This is how:
```javascript
<li v-for="todo in hideCompletedTodos" :key="todo.id">
<button @click="removeTodo(todo)">X</button>
</li>
```

As you can notice, `todo` is a local variable that represents each object in `hideCompletedTodos` ('hideCompletedTodos' returns filtered `todos` or original `todos` array, remmeber?) By using `@click` method we trigger  `removeTodo(todo)` function that takes its parameter from `todo` local variable. _Their names **have to match** because `todo` local variable is the argument for `removeTodo(todo)`_

```javascript
<button @click="hideCompleted = !hideCompleted">
    {{ hideCompleted ? 'Show all' : 'Hide completed' }}
  </button>
```

The code above changes state of `hideCompleted`. `hideCompleted` is a boolean value, so the code above turns it to the opposite of the current value. 

That's it for part 3, we talked about computed properties, and difference between a computed property and a method property in Vue.js.

Next, I will be going through Life Cycle and Template Refs, and maybe Watchers.