Search code examples
listvue.jscheckboxitems

Issue with marking of checkboxes in the list of items


I have a Vue app: it is To Do List, where after adding some notes by clicking button Add Task we receive a list of items to do. On the front of each item we have button Delete and checkbox to have opportunity to mark it as done. The bug is when I for example mark one of the items in the list as checked and after that delete it-marker that it was checked goes to the other item which was not marked as checked initially. Can you please advice how it can be solved using Vue.js or any other option? Below is my code:

Vue.createApp({
    data(){
        return{
          placeholder: 'Start typing',
          inputvalue: '',
          notes: []
        }
    },
    mounted() {
        this.notes = JSON.parse(localStorage.getItem('note')) || [];
      },
      watch: {
            notes: {
                handler: function() {
                    localStorage.setItem('note', JSON.stringify(this.notes));
                },
                deep: true
            }
        },
    methods: {
        addnewtask(){
            if (this.inputvalue !== ''){
                this.notes.push(this.inputvalue)
                this.inputvalue=''
            }
        },
        removetask(index){
            if (confirm('Do you really want to delete?'))
            this.notes.splice(index, 1)
        }
    }
}).mount(app)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>To Do List</title>
</head>
<link rel="stylesheet" href="style.css">
<body>
    <div class="container" id="app">
      <div class="card">
          <h1>To Do List</h1>
          <div class="form-control">
             <input
                 type="text" 
                 v-bind:placeholder="placeholder" 
                 v-model="inputvalue"
                 v-on:keypress.enter="addnewtask"
              />
              <button class="btn" v-on:click="addnewtask">Add Task</button>
            </div>
            <hr />
            <ul class="list" v-if="notes.length !== 0"...>
                <li class="list-item" v-for="(note, index) in notes">
                    <div>
                        <input type="checkbox"/>
                        ({{index+1}}) {{note}}
                    </div>
                    <button class="btn danger" v-on:click="removetask(index)">Delete</button>
                </li>
                <hr />
                <li>
                    <strong>Total: {{notes.length}}</strong>
                </li>
            </ul>
            <div v-else>No task exist, please add first one.</div>
      </div>
    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="Vue3.js"></script>
</body>
</html>


Solution

  • The main issue in you code is, you don't store any information about which task is checked and which one is not.let's say you checked 3rd task and then delete it, the new 3rd item from the top will be auto checked as it has no information about the task so can't differentiate between the new and the deleted task.

    This can be solved many way one easy solution is, in your notes array store two types of data. One title and one is isChecked then v-model the checked value in template.

    Update your addnewtask() function like this,

        addnewtask() {
          if (this.inputvalue !== "") {
            this.notes.push({
              title: this.inputvalue,
              isChecked: false,
            });
            this.inputvalue = "";
          }
        },
    

    In html use a v-modal to add a two way data binding for the note.isChecked and update note like note.title since note is currently an object now.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>To Do List</title>
      </head>
      <link rel="stylesheet" href="style.css" />
      <body>
        <div class="container" id="app">
          <div class="card">
            <h1>To Do List</h1>
            <div class="form-control">
              <input
                type="text"
                v-bind:placeholder="placeholder"
                v-model="inputvalue"
                v-on:keypress.enter="addnewtask"
              />
              <button class="btn" v-on:click="addnewtask">Add Task</button>
            </div>
            <hr />
            <ul class="list" v-if="notes.length !== 0" ...>
              <li class="list-item" v-for="(note, index) in notes">
                <div>
                  <input type="checkbox" v-model="note.isChecked" />
                  ({{index+1}}) {{note.title}}
                </div>
                <button class="btn danger" v-on:click="removetask(index)">
                  Delete
                </button>
              </li>
              <hr />
              <li>
                <strong>Total: {{notes.length}}</strong>
              </li>
            </ul>
            <div v-else>No task exist, please add first one.</div>
          </div>
        </div>
        <script src="https://unpkg.com/vue@next"></script>
        <script src="Vue3.js"></script>
      </body>
    </html>
    
    
    

    Here is a vue playgroud link for your code demo.