LocalStorage in Vue App with multiple inputs

2019-08-23 11:30发布

i dont know if this is possible - but i am working on a Vue app with multiple input fields that posts to the same list - and i need this to be stored somehow, so when you refresh the site, the outputs from the input fields are saved.

This means both the taskList and subTaskList array should be saved ( i know i've only worked on taskList ).

The example i posted here saves the data fine, however if you refresh, it will post all the data in all the components, can this be fixed so it will only be in the right components?

const STORAGE_KEY = 'madplan-storage'

Vue.component('list-component', {
            data: function() {
                return {
                    newTask: "",
                    taskList: [],
                    newSubTask: "",
                    subTaskList: [],
                };
            },

            created() {
              this.taskList = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
            },

            template:
                '<div>' +

                '<section class="prefetch">' +
                '<input  v-if="showInput" class="input typeahead" type="text" placeholder="Tilføj ret til madplanen" v-model="newTask" v-on:keyup.enter="addTask">' +
                '</section>' +

                '<details open v-for="task in taskList" v-bind:key="task.text" class="sub-list-item">' +
                '<summary>{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeTask(task)"></i>' + '</summary>' +
                '<input class="subInput" type="text" placeholder="Tilføj til indøbsseddel" v-model="newSubTask" v-on:keyup.enter="addSubTask">' +
                '</details>' +

                '</div>',

            computed: {
                showInput: function() {
                    return !this.taskList.length
                },
            },

            methods: {
                //addTasks
                //
                addTask: function() {
                    var task = this.newTask.trim();
                    if (task) {
                        this.taskList.push({
                            text: task
                        });
                        this.newTask = "";
                        localStorage.setItem(STORAGE_KEY, JSON.stringify(this.taskList));
                    }
                },

                addSubTask: function() {
                    var task = this.newSubTask.trim();
                    if (task) {
                        this.subTaskList.push({
                            text: task
                        });
                        this.newSubTask = "";
                        this.$emit('addedtask', task);
                        localStorage.setItem(STORAGE_KEY, JSON.stringify(this.subTaskList));
                    }
                },

                //removeTasks
                //
                removeTask: function(task) {
                    var index = this.taskList.indexOf(task);
                    this.taskList.splice(index, 1);
                },
            },
        });



        new Vue({
            el: "#madplan",
            data: {
                newTask: "",
                taskList: [],
                newSubTask: "",
                subTaskList: [],
            },
            methods: {
              acknowledgeAddedTask: function(cls, task) {
                this.$data.subTaskList.push({
                	text: task,
                  class: "list-item " + cls
                  })
              },
              acknowledgeRemovedTask: function(task) {
                this.$data.subTaskList = this.$data.subTaskList.filter(it => it.text != task.text)
              },
              removeSubTask: function(task) {
                  var index = this.subTaskList.indexOf(task);
                  this.subTaskList.splice(index, 1);
              },
            }
        });
    <section id="madplan" class="section-wrapper">

        <section class="check-list">
          <div id="mandag" class="dayWrapper">
            <h1>Day One</h1>
            <list-component
              class="mandag"
              v-on:addedtask='task => acknowledgeAddedTask("mandag", task)'
            ></list-component>
          </div>

          <div id="tirsdag" class="dayWrapper">
            <h1>Day Two</h1>
            <list-component
              class="tirsdag"
              v-on:addedtask='task => acknowledgeAddedTask("tirsdag", task)'
            ></list-component>
          </div>
          
        <ul id="indkobsseddel">
            <h2>Shopping List</h2>
            <li v-for="task in subTaskList" v-bind:key="task.text" :class="task.class">{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeSubTask(task)"></i></li>
        </ul>

     </section>
     
     <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://unpkg.com/vue/dist/vue.js" charset="utf-8"></script>

To be clear, i will come with an example: As it is now, if i post "Foo" and "Bar" to the "Day One" component and refresh the page, it will then post "Foo" and "Bar" to both "Day One" and "Day Two". Essentially, i would like to be able to post for an example "Foo" to "Day One", "Bar" to "Day Two" and from there post "Hello World" to the Shopping List, and it would all be saved in the right places, instead of posting everything everywhere.

BTW: I'm a scrub at backend work.

1条回答
等我变得足够好
2楼-- · 2019-08-23 12:13

To persist global state, you may use the plugin vue-persistent-state like this:

import persistentStorage from 'vue-persistent-storage';

const initialState = {
  newTask: "",
  taskList: [],
  newSubTask: "",
  subTaskList: [],    
};
Vue.use(persistentStorage, initialState);

Now newTask, taskList, newSubTask and subTaskList is available as data in all components and Vue instances. Any changes will be stored in localStorage, and you can use this.taskList etc. as you would in a vanilla Vue app.

Your list component now becomes:

Vue.component('list-component', {
  // data removed
  // created removed

  template:
    '<div>' +

    '<section class="prefetch">' +
    '<input  v-if="showInput" class="input typeahead" type="text" placeholder="Tilføj ret til madplanen" v-model="newTask" v-on:keyup.enter="addTask">' +
    '</section>' +

    '<details open v-for="task in taskList" v-bind:key="task.text" class="sub-list-item">' +
    '<summary>{{ task.text }}<i class="fa fa-times" aria-hidden="true" v-on:click="removeTask(task)"></i>' + '</summary>' +
    '<input class="subInput" type="text" placeholder="Tilføj til indøbsseddel" v-model="newSubTask" v-on:keyup.enter="addSubTask">' +
    '</details>' +

    '</div>',

  computed: {
    showInput: function() {
      return !this.taskList.length
    },
  },

  methods: {
    //addTasks
    //
    addTask: function() {
      var task = this.newTask.trim();
      if (task) {
        this.taskList.push({
          text: task
        });
        this.newTask = "";
        // localStorage.setItem not needed
      }
    },

    addSubTask: function() {
      var task = this.newSubTask.trim();
      if (task) {
        this.subTaskList.push({
          text: task
        });
        this.newSubTask = "";
        // $emit not needed, state is global and shared
        // localStorage.setItem not needed
      }
    },

    //removeTasks
    //
    removeTask: function(task) {
      var index = this.taskList.indexOf(task);
      this.taskList.splice(index, 1);
    },
  },
});

If you want to understand how this works, the code is pretty simple. It basically

  1. adds a mixin to make initialState available in all Vue instances, and
  2. watches for changes and stores them.

Disclaimer: I'm the author of vue-persistent-state.

查看更多
登录 后发表回答