user10991526
user10991526

Reputation: 135

How can I keep number and increment in child component with Vue JS?

Practicing to make a todo application with Vue JS

Input items save in the localStrage.

UPDATED

When you have some added list and reload a page, ID number start from 1(defalut).

Ideal behaviour:

My code: Link

Problem is around here.

Child2.vue

  created() {
    let keyObject = JSON.parse(localStorage.getItem(this.keyName));

    if (keyObject) {
      this.$emit("update:todos", keyObject);
    } else {
      return;
    }

    if (this.todos.length > 0) {
      console.log(this.todos.id);
      const setId = this.todos.reduce(function(a,b){ return a > b.id ? a : b.id} ,0)
      this.todos.id = setId + 1
      console.log(this.todos.id);

      this.$emit('update:todos', keyObject)
      // this.$emit('update:todos', this.todos.id)
    }
  },

Do you know how?

Upvotes: 1

Views: 1774

Answers (3)

Hans Felix Ramos
Hans Felix Ramos

Reputation: 4424

You can avoid modify props directly using .sync modifier:

App.vue:

<Child2 :todos.sync="todos" :keyName="keyName"/>

Child2.vue:

if (keyObject) {
     this.$emit('update:todos', keyObject);
}

For get the next id, you can emit this value when you get the array from local storage:

App.vue:

<Child2 :todos.sync="todos" @setTargetId="setTargetId" :keyName="keyName"/>
methods: {
    // ...
    setTargetId(newTargetId){
        this.$set(this.target, 'id', newTargetId );
    }
}

Child2.vue:

// ...
created() {
    let keyObject = JSON.parse(localStorage.getItem(this.keyName));

    // Check keyObject 
    if (keyObject) {
        // update todo on App.vue
        this.$emit("update:todos", keyObject);

        // set target.id
        const setId = keyObject.reduce(function(a,b){ return a > b.id ? a : b.id} ,0)
        this.$emit('setTargetId', setId + 1)
    } 
},

See here: https://codesandbox.io/s/keen-gates-q7efo

Upvotes: 1

Karl L
Karl L

Reputation: 1725

There is inconsistent formatting in keyObject and this.todos( this.todos is actually nested), and you are not suppose to mutate props.

ALSO NOTICE THE ID INCREMENTATION TO AVOID DUPLICATE ERROR IN LOOPS

My suggestion App.vue:

methods: {
    addBtn() {

      const todo = { id: this.target.id, name: this.target.name, done: false };
      this.todos.push(todo);
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
      this.target.name = "";
      //it is important to increment the id based on current length
      this.target.id = this.todos.length + 1;
    },
    onInputChange(val) {
      this.target.name = val;
    }
  },
  created() {
     let todosObject  = JSON.parse(localStorage.getItem(this.keyName));
     if(todosObject){
       this.todos = todosObject
       //again base the id on the current length, to avoid duplicate error in loops later 
       this.target.id = this.todos.length+1
     }

  }

Child2:

<template>
  <div>
    <ul>
      <li v-for="todo in todos" :key="todo.id">
        ID: {{ todo.id }} / Name: {{ todo.name }}
        <input
          type="checkbox"
          v-model="todo.done"
          @click="status(todo)"
        >
        <button @click="removeBtn(todo)">Remove item</button>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  props: {
    todos: {
      type: Array,
      required: true
    },
    keyName: {
      type: String,
      required: true
    }
  },

  methods: {
    removeBtn(item) {
      const index = this.todos.indexOf(item);
      this.todos.splice(index, 1);
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
      if (this.todos.length === 0) {
        console.log("no item");
      }
    },
    status(todo) {
      todo.done = !todo.done;
      localStorage.setItem(this.keyName, JSON.stringify(this.todos));
    }
  }
};
</script>

Upvotes: 2

Jakub A Suplicki
Jakub A Suplicki

Reputation: 4801

From my understanding of your problem, you want to update the value of the props from a child component.

To do that you might want to emit the change from a child component back to the parent.

Below is one way of doing that:

In your child component:

this.todosArray = this.todosArray.concat(keyObject); //concat with an existing array
this.$emit("updateTodos", this.todosArray); //emit new array back to parent

In your parent component, where u register your child component:

<Child2 :todos="todos" :keyName="keyName" @updateTodos="updateTodos"/>

and then add a method to update the original array with the value that will come from the child component.

updateTodos(value) {
 this.todos = value
}

I hope it helps. Good luck!

Upvotes: 1

Related Questions