TYzzz
TYzzz

Reputation: 3

Why computed property works on preserving the reactivity but attributes in data() {} does not

I'm following this tutorial, where they point out a small bug with the checkbox status of forgetting the state of the ticked/unticked which can be solved by using the computed property.

I would like to ask, even if the attribute isDone in Data (ToDoItem.vue) has been changed to true (by ticking the checkbox), why the box is still unticked after clicking edit then cancel, and why computed property could solve this bug.

Below are parts of the scripts.

ToDoItem.vue

    <template>
  <div class="stack-small" v-if="!isEditing">
    <div class="custom-checkbox">
      <input
        type="checkbox"
        class="checkbox"
        :id="id"
        :checked="isDone"
        @change="$emit('checkbox-changed')"
      />
      <label :for="id" class="checkbox-label">{{ label }}</label>
    </div>
    <div class="btn-group">
      <button
        type="button"
        class="btn"
        ref="editButton"
        @click="toggleToItemEditForm"
      >
        Edit <span class="visually-hidden">{{ label }}</span>
      </button>
      <button type="button" class="btn btn__danger" @click="deleteToDo">
        Delete <span class="visually-hidden">{{ label }}</span>
      </button>
    </div>
  </div>
  <to-do-item-edit-form
    v-else
    :id="id"
    :label="label"
    @item-edited="itemEdited"
    @edit-cancelled="editCancelled"
  ></to-do-item-edit-form>
</template>

<script>
import ToDoItemEditForm from "./ToDoItemEditForm";

export default {
  components: {
    ToDoItemEditForm,
  },

  props: {
    label: { required: true, type: String },
    done: { default: false, type: Boolean },
    id: { required: true, type: String },
  },

  data() {
    return {
      isEditing: false,
      isDone: this.done, // after deleting this line and use 
                         //computed: {} below, the bug is solved.
    };
  },
  
  // computed: {
  //   isDone() {
  //     return this.done;
  //   },
  // },
};
</script>

ToDoItem.vue

<template>
  <div id="app">
    <h1>To-Do List</h1>
    <to-do-form @todo-added="addToDo"></to-do-form>
    <h2 id="list-summary" ref="listSummary" tabindex="-1"> {{ listSummary }} </h2>
    <ul aria-labelledby="list-summary" class="stack-large">
      <li v-for="item in ToDoItems" :key="item.id">
        <to-do-item
          :label="item.label"
          :done="item.done"
          :id="item.id"
          @checkbox-changed="updateDoneStatus(item.id)"
          @item-deleted="deleteToDo(item.id)"
          @item-edited="editToDo(item.id, $event)"
        >
        </to-do-item>
      </li>
    </ul>
  </div>
</template>

 <script>
 import ToDoItem from "./components/ToDoItem.vue";
 import ToDoForm from "./components/ToDoForm.vue";
 import uniqueId from "lodash.uniqueid";

 export default {
    name: "app",
    components: {
    ToDoItem,
    ToDoForm,
    },

  data() {
    return {
      ToDoItems: [],
    };
  },

methods: {
  updateDoneStatus(toDoId) {
    const toDoToUpdate = this.ToDoItems.find((item) => item.id === toDoId);
    toDoToUpdate.done = !toDoToUpdate.done;
    console.dir(toDoToUpdate.done)
  },
};
</script>

Upvotes: 0

Views: 55

Answers (1)

Damzaky
Damzaky

Reputation: 10826

I'm not an expert in vue, but I believe that the this.done being assigned to isDone: is only done once in data(), and it wouldn't be done if the props change (the value of isDone in data() won't change when the prop done changes). While in computed, isDone will watch the done prop value, and if that prop value changes, the computed will be notified and thus changes the isDone data.

Upvotes: 1

Related Questions