首页 > 解决方案 > 我应该如何动态更新firebase文档

问题描述

我正在使用 JS 和 Firebase 为我的投资组合开发一个简单的笔记应用程序。在我告诉你发生了什么之前,我觉得我需要向你展示我的代码是如何工作的,如果你有任何提示和疑虑,请告诉我,我们将不胜感激。话虽如此,让我们“一起”看看。我正在使用这个类来创建笔记:

 const htmlElements = [document.querySelector('.notes'), document.querySelector('.note')];
 const [notesDiv, noteDiv] = htmlElements;
 
 class CreateNote {
   constructor(title, body) {
     this.title = title;
     this.body = body;
     this.render = () => {
     const div1 = document.createElement('div');
     div1.className = 'notes-prev-container';

     div1.addEventListener('click', () => { this.clickHandler(this) });

     const div2 = document.createElement('div');
     div2.className = 'notes-prev';

     const hr = document.createElement('hr');
     hr.className = 'notes__line';

     // Nest 'div2' inside 'div1'

     div1.appendChild(div2);
     div1.appendChild(hr);

    /*
       Create Paragraph 1 & 2 and give them the same
       class name and some text
    */

      const p1 = document.createElement('p');
      p1.className = 'notes-prev__title';
      p1.innerText = this.title;

      const p2 = document.createElement('p');
      p2.className = 'notes-prev__body';
      p2.innerText = this.body;

      // Nest p 1 & 2 inside 'div2'

      div2.appendChild(p1);
      div2.appendChild(p2);

      // Finally, render the div to its root tag

      notesDiv.appendChild(div1);
    }
  }

  /* 
    Every time this method is called, it creates 2 textareas, 
    one for the note title and the other for its body then it 
    appends it to the DOM.
  */

  renderNoteContent () {
    const title = document.createElement('textarea');
    title.placeholder = 'Title';
    title.value = this.title;
    title.className = 'note__title';
    
    const body = document.createElement('textarea');
    body.placeholder = 'Body';
    body.value = this.body;
    body.className = 'note__body';

    noteDiv.appendChild(title);
    noteDiv.appendChild(body);
  }

   /*
    When this method is called, it checks to see if there's a 
    note rendered already (childElementCount === 1 because there's a 
    button, so if there's only this button it means there's no 
    textareas rendered).
    
    If yes, then merely call the renderNoteContent method. Else
    get the tags with the classes 'note__title' and 'note__body'
    and remove them from the DOM, then call renderNoteContent to 
    create the textareas with the clicked notes values.

    This function gets mentioned at line 19.
  */

  clickHandler(thisClass) {
    if (noteDiv.childElementCount === 1) {
       thisClass.renderNoteContent();
    } else {
      document.querySelector('.note__title').remove();
      document.querySelector('.note__body').remove();
      thisClass.renderNoteContent();
    }
  }
}

现在我需要2个按钮,createNotesButton分别saveNotesButton。这 2 个按钮必须位于将在内部调用的函数内.onAuthStateChanged(为什么?因为它们需要访问currentUseron firebase 身份验证)。

我想createNotesButton创建一个便笺原型,将其渲染到 DOM 并在 firestore 上创建一个新文档,该便笺内容将存储在其中。我是这样做的:

PS:我觉得我没有正确使用这个类,所以如果你有任何提示,我很感激。

import {db} from '../../firebase_variables/firebase-variables.js';
import {CreateNote} from '../create_notes_class/create_notes_class.js';

const htmlElements = [
  document.querySelector('.createNotes-button'), 
  document.querySelector('.saveNotes-button')
];

const [createNotesButton, saveNotesButton] = htmlElements;


function clickHandler(user) {
 
 /*

   1. Creates a class.

   2. Creates a new document on firebase with the class's empty value.

   3. Renders the empty class to the DOM.

 */

  createNotesButton.addEventListener('click', () => {

  const note = new CreateNote('', '');
  note.render();

 // Each user has it's own note collection, said collection has their `uid` as name.

    db.collection(`${user.uid}`).doc().set({
      title: `${note.title}`,
      body: `${note.body}`
    })
  })

}

现在我需要一个saveNotesButton,他是我遇到问题的人。他需要将显示的便笺内容保存在 Firestore 上。这是我尝试做的事情:

import {db} from '../../firebase_variables/firebase-variables.js';
import {CreateNote} from '../create_notes_class/create_notes_class.js';

const htmlElements = [
  document.querySelector('.createNotes-button'), 
  document.querySelector('.saveNotes-button')
];

const [createNotesButton, saveNotesButton] = htmlElements;

function clickHandler(user) {
 
  createNotesButton.addEventListener('click', () => {...}) 

  /*

    1. Creates 2 variables, `title` and `body, if there's not a note being displayed
       their values will be null, which is why the rest of the code is inside an if
       statement

    2. If statement to check if there's a note being displayed, if yes then:
       
       1. Call the user's note collection. Any document who has the title field equal to the
          displayed note's value gets returned as a promise.

       2. Then call an specific user document and update the fields `title` and `body` with 
          the displayed note's values.

    3. If no then do nothing.

  */

  saveNotesButton.addEventListener('click', () => {

    const title = document.querySelector('.note__title');
    const body = document.querySelector('.note__body');


    db.collection(`${user.uid}`).where('title', '==', `${title.value}`)
      .get()
        .then(userCollection => {
          db.collection(`${user.uid}`).doc(`${userCollection.docs[0].id}`).update({
            title: `${title.value}`,
            body: `${body.value}`
          })
      })
      .catch(error => {
        console.log('Error getting documents: ', error);
      });
    });

}

这不起作用,因为我将title.value其用作查询,因此如果我更改它的值,它也会将查询方向更改为不存在的路径。

那么问题来了:我怎样才能让 saveNotesButton 完成它的工作?我正在考虑为每个便笺添加另一个字段,该字段不会更改,因此我可以轻松识别和编辑每个便笺。同样,如果您认为我的代码中的某些内容可以或应该被格式化,请告诉我,我正在使用这个项目来巩固我的原生 JS 知识,所以请耐心等待。我觉得如果我使用过 React,我会在一段时间前完成这个,但肯定不会学到很多东西,无论如何提前感谢您的帮助。

标签: javascriptfirebaseclassgoogle-cloud-firestore

解决方案


我正在考虑为每个便笺添加另一个字段,该字段不会更改,因此我可以轻松识别和编辑每个便笺。

是的,对于 firestore 中的每个便笺文档,您绝对需要一个不可变的标识符,以便您可以明确地引用它。每当您在具有任何数据库的任何应用程序中存储数据对象时,您几乎总是需要这个。

但是,firestore 已经为您执行了此操作:调用后,db.collection(user.uid).doc()您应该得到一个带有 ID的文档。这是您在更新笔记时要使用的 ID。

与 DOM 交互的代码部分需要跟踪这一点。我建议将创建 firestore 文档的代码移动到构造函数中CreateNote并将其存储在this. 您还需要那里的用户 ID。

  constructor(title, body, userId) {
     this.title = title;
     this.body = body;
     const docRef = db.collection(userId).doc();
     this.docId = docRef.id;

     /* etc. */

然后,只要您有 的实例CreateNote,您就会知道要引用的正确用户和文档。

其他建议(因为你问过)

  • 使用 JsPrettier。这是值得的设置,你永远不会回去。
  • 正确使用 HTML 语义。Div 不应该作为 hrs 的子级附加,因为它们用于“段落级元素之间的主题中断:例如,故事中的场景变化,或章节内的主题转移”。MDN
  • 对于您的下一个项目,请使用框架。基本上没有人手动编码事件监听器并附加孩子来完成事情。我看到了基本理解的价值,但是那里有一个丰富而美丽的框架世界;不要通过避免它们来限制自己:-)

推荐阅读