0
votes

I have a parent component (todo-list) with a child component inside (todo-item). I am trying to create a checkbox(check all todos) in the parent so that when all todos will be checked with one click.

With the checkAll() in the parent component, it change the props of the child but it does not change the data of the child.

enter image description here

This is the parent component todo-list

<template>
  <div class="todo-list-container">
    <todo-input @addTodo="addTodo"></todo-input>
    <todo-item v-for="(todo, index) in todos" 
      :key="todo.id" 
      :todo="todo" 
      :index="index" 
      :completed="todo.completed"
      @removeTodo="removeTodo"
      @changedCompleted="changedCompleted"
    ></todo-item>
    <div class="flex-container">
      <div class="button-aux-div"></div>
      <a href="#" class="todo-button">
        <input type="checkbox" :checked="!anyRemaining" @change="checkAll">
      </a>
    </div>
  </div>
</template>

<script>

import Vue from 'vue'
import TodoItem from './TodoItem'
import TodoInput from './TodoInput'

export default {
  name: 'todo-list',

  components: {
    TodoItem,
    TodoInput,
  },

  data () {
    return {
      idForTodo: 3,
      todos: [
        {
          'id': '1',
          'title': 'title1',
          'body': 'body1',
          'completed': false,
        },
        {
          'id': '2',
          'title': 'title2',
          'body': 'body2',
          'completed': false,
        },
      ],
      allChecked: false,
    }
  },

  computed: {
    remaining() {
      return this.todos.filter(todo => !todo.completed).length
    },
    anyRemaining() {
      return this.remaining != 0
    }
  },

  methods: {
    addTodo(todoMessage) {
      this.todos.push({
        id: this.idForTodo,
        title: 'title' + this.idForTodo,
        body: todoMessage,
        completed: false,
      })

      this.idForTodo++;
    },

    removeTodo(data) {
      this.todos.splice(data.index, 1);
      this.idForTodo--;
    },

    changedCompleted(data) {
      this.todos.splice(data.index, 1, data.todo)
    },

    checkAll() {
      this.todos.forEach((todo) => todo.completed = event.target.checked)
    },
  },

}
</script>

This is the child componenet todo-item

<template>
  <div class="todo-item-container">
    <div class="todo-title-container">
      <div class="todo-id-container">
        <div id="todo-id">
          <h2>{{ id }}</h2>
        </div>
      </div>
      <div id="todo-title"><h2>{{ title }}</h2></div>
      <div class="todo-completed-container">
        <a href="#" class="todo-button">
          <input type="checkbox" v-model="completed" @change="changedCompleted">
        </a>
      </div>
      <div class="todo-delete-container">
        <a href="#" class="todo-button" @click="deletedTodo">×</a>
      </div>
    </div>

    <hr>

    <div class="todo-body-container">
      <p id="todo-body">{{ body }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'TodoItem',

  props: {
    todo : {
      type: Object,
      required: true,
    },
    index : {
      type: Number,
      required: true,
    },
  },

  data () {
    return {
      'id': this.todo.id,
      'title': this.todo.title,
      'body': this.todo.body,
      'completed': this.todo.completed,
    }
  },  

  methods: {

    deletedTodo() {
      this.$emit('removeTodo', {
        'index': this.index,
        'todo': {
          'id': this.id,
          'title': this.title,
          'body': this.body,
          'completed': this.completed,
        }
      })
    },

    changedCompleted() {
      this.$emit('changedCompleted', {
        'index': this.index,
        'todo': {
          'id': this.id,
          'title': this.title,
          'body': this.body,
          'completed': this.completed,
        }
      })
    },
  },
}

</script>
1
I am not seeing - completed prop get received by child-componentSatyam Pathak
below @subhasis suggested to add a computed property. But do I need to pass the completed prop from my parent to child? As it has already been included in the todo item.sammyyy
props are reactive, you don't need to put it into computed. It's probably not working here cuz object are reference values and you are passing a address of the object so any update inside need to get deeply watched.Now - if you pass completed prop to child and whenever completed get updated child will get the updated value.Satyam Pathak
when i passed the completed prop to the child component, yes it update the prop as well as the data 'completed' in the child component. But still, when I try to checkall, the prop changes in the parent component but it does not change the data 'completed' in the child component.sammyyy

1 Answers

0
votes

Instead of 'completed': this.todo.completed, . Use

computed: {
  completed () {
    return this.todo.completed
  }
}