Search code examples
firebasevue.jsgoogle-cloud-firestoreautosave

I have a problem with autosaving data in VueJS, the autosave doesn't complete when I change the current note


so I have a problem this problem with my app. I'm not sure what is the right way to implement this autosaving feature. When you change the note's title or it's content, there is a debounce function that goes off in 2 seconds and if you change to the current note before the debounce update is complete it never updates. Let me know if I've done a poor job of explaining or if there is something that I need to clarify, Thanks!

Here's a video of what occurs: https://www.loom.com/share/ef5188eec3304b94b05960f403703429

And these are the important methods:

    updateNoteTitle(e) {
      this.noteData.title = e.target.innerText;
      this.debouncedUpdate();
    },
    updateNoteContent(e) {
      this.noteData.content = e;
      this.debouncedUpdate();
    },
    debouncedUpdate: debounce(function () {
      this.handleUpdateNote();
    }, 2000),
    async handleUpdateNote() {
      this.state = "loading";
      
      try {
        await usersCollection
          .doc(this.userId)
          .collection("notes")
          .doc(this.selectedNote.id)
          .update(this.noteData)
          .then(() => this.setStateToSaved());
      } catch (error) {
        this.state = "error";
        this.error = error;
      }
    },
    setStateToSaved() {
      this.state = "saved";
    },

Solution

  • Why running every two seconds ?

    To autosave the note I recommend that you add an eventListener on window closing or on changing the tab event, Like in the video provided (whatever event suits you best)

    created () {    
            window.addEventListener('beforeunload', this.updateNote)  
        }
    

    Where your updateNote function is not async.

    But if you really want to save on each change. You can make a computed property that looks like this:

       note: {
          get() {
            return this.noteData.title;
          },
          set(value) {
            this.noteData.title = value;
            this.state= 'loading'
            usersCollection.doc(this.userId)
                           .collection("notes")
                           .doc(this.selectedNote.id)
                           .update(this.noteData)
                           .then(() => this.setStateToSaved());
          }
        },
    

    And the add v-model="note" to your input. Imagine the user will type 10 characters a second That's 10 calls meaning 10 saves

    EDIT:

    Add a property called isSaved. On Note change click if(isSaved === false) call your handleUpdateNote function.

    updateNoteTitle(e) {
      this.noteData.title = e.target.innerText;
      this.isSaved = false;
      this.debouncedUpdate();
    }
    

    and in your function setStateToSaved add this.isSaved = true ; I don't know if your side bar is a different component or not. If it is, and you are using $emit to handle the Note change, then use an event listener combined with the isSaved property.