Adding additional data to the local storage in Vue.js

Viewed 32

I have an app To Do List. Using button you add task and new task adds to the list of items with checkbox and delete button in front of each one. I want to save all value from inputs and marked chekboxes on page (store it) once page renewed using browser. To do it I`m using mounted and watch, for now it stores only value from inputs, but not marked chekboxes. Please help to fix it. Below my code:

Vue.createApp({
    data(){
        return{
          placeholder: 'Start typing',
          inputvalue: '',
          notes: [],
          checked: []
        }
    },
    mounted() {
  try {
    this.notes = JSON.parse(localStorage.getItem('note'))
  } catch(e) {
    this.notes = []
  }
},
      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)
body {
    font-family: sans-serif;
    font-size: 14px;
    color: #030303;
    background: #3d5f82;
}
h1 {
    font-weight: 500;
    text-transform: uppercase;
    text-align: center;
    font-style: solid;
}
.btn {
    color: #31d78c;
    place-content: center;
    place-items: center;
    width: fit-content;
    border-radius: 99px;
    border: 1px solid #31d78c;
    text-decoration: none;
    text-transform: uppercase;
    margin-right: 10px;
    margin-top: 10px;
    padding: 10px;
    font-weight: 700;
    background: #fff;
}
.btn:hover {
    cursor: pointer;
    background-color:rgb(231, 239, 235);
}
.btn.danger {
    color: #eb3c15;
    place-content: center;
    place-items: center;
    width: fit-content;
    border-radius: 99px;
    border: 1px solid #eb3c15;
    text-decoration: none;
    text-transform: uppercase;
    margin-right: 10px;
    margin-top: 10px;
    padding: 10px;
    font-weight: 700;
    background: #fff;
}
.btn.danger:hover {
    cursor: pointer;
    background-color:rgb(236, 219, 219);
}
.container {
    margin: 0 auto;
    max-width: 1000px;
}
.form-control {
    position: relative;
    margin-bottom: 10px;
}
.form-control input,
.form-control select {
    margin: 0;
    outline: none;
    border: 2px solid #ccc;
    display: block;
    width: 95%;
    color: #2c3e50;
    padding: 0.5rem 1.5rem;
    border-radius: 3px;
    font-size: 1rem;
}
.card {
    overflow: hidden;
    padding: 1rem;
    margin-bottom: 1rem;
    border-radius: 10px;
    box-shadow: 2px 3px 10px rgba(0, 0, 0, 0.2);
    background: #fff;
}
.card.center {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.list {
    margin: 0;
    padding: 0;
    list-style: none;
}
.list-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0;
    transition: .22s all;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
}
<!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">
<style>
    [v-cloak] {
        display:none;
    }
</style>
<body>
    <div class="container" id="app" v-cloak>
      <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" v-bind:key="note">
                    <div>
                        <input type="checkbox" v-model="checked[note]"/>
                        <span :style="checked[note] ? 'text-decoration: line-through' : ''">
                            {{index+1}}) {{note}}
                        </span>
                    </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>

1 Answers

I would recommend storing the checkbox value inside your items array instead of separately storing which items are selected. For example you could store this array of objects:

[
  {
    title: "Title",
    selected: true
  }
]

Then use the item.selected value inside your checkbox to mark it selected or not selected.

On a second note, instead of manually storing your data in localStorage, I'd recommend using Vuex with localStorage (https://medium.com/js-dojo/how-to-permanently-save-data-with-vuex-localstorage-in-your-vue-app-f1d5c140db69)

You can set it up such that it automatically stores your Vuex state in localStorage and when you refresh the page it will reload it back into your state. Hope this helps!

Related