sammyyy
sammyyy

Reputation: 343

Vue Component Communication (Parent > Children)

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>

Upvotes: 0

Views: 290

Answers (1)

subhasis
subhasis

Reputation: 298

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

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

Upvotes: 0

Related Questions