创建更多数据时,渲染期间复制数据(Firebase Firestore)

njthzxwz  于 2023-01-14  发布在  其他
关注(0)|答案(1)|浏览(102)

在渲染的时候,数据被复制了,正如我之前评论的那样,我相信这是因为我试图插入一行,添加类“space”来在数据之间放置空间,但是我不知道如何添加空间,而不需要复制我在添加时创建的每个数据。这是我在Firebase中可视化和渲染数据的代码:

function renderTable() {
db.collection('xxx').get().then((snapshot) => {
  snapshot.forEach((doc) => {
    // Adds one row to the table for each document
    var row = document.getElementById('tabla-datos').insertRow(-1);
    
    var cell1 = row.insertCell(0);
    var cell2 = row.insertCell(1);
    var cell3 = row.insertCell(2);
    var cell4 = row.insertCell(3);
    var cell5 = row.insertCell(4);
    var cell6 = row.insertCell(5);
    var cell7 = row.insertCell(6);
    cell1.innerHTML = doc.data().a;
    cell2.innerHTML = doc.data().b;
    cell3.innerHTML = doc.data().c;
    cell4.innerHTML = doc.data().d;
    cell5.innerHTML = doc.data().e;
    cell6.innerHTML = doc.data().fr;
    cell7.innerHTML = '<a href="#">Ver</a> | <a href="#">Edit</a> | <a href="#">Delet</a>';
     // Creates a new empty row at the end of the table
     let rows = document.getElementById('tabla-datos').insertRow(-1);

     // Assigns the class "space" to the row
     rows.classList.add("space");
    });
});

}

db.collection("Productos").onSnapshot(function() {
  renderTable();
});

下面是css中留空格的代码:

tr.space{
    height:10px;
    border-bottom-width: 0px;
    background-color: #ffffff;
  }

如果你想知道的话,我目前正在运行连接到firebase的javascript。

hk8txs48

hk8txs481#

使用这些代码行,无论何时更新集合(即添加、删除和/或更新数据),都可以调用renderTable()函数。

db.collection("Productos").onSnapshot(function() {
  renderTable();
});

但是在renderTable()函数中,无论现有表是否存在,都要向现有表中插入新行,而且没有任何代码来处理从查询结果中删除的数据。

db.collection('xxx').get().then((snapshot) => {
  snapshot.forEach((doc) => {
    // Adds one row to the table for each document
    var row = document.getElementById('tabla-datos').insertRow(-1);
    
    // ...
  }
})

为了纠正这一点,我们首先创建一个函数,将DocumentSnapshot添加到给定的table元素中:

function insertRowForDocument(tableEle, docSnap, index = -1) {
  const rowEle = tableEle.insertRow(index);

  const { a, b, c, d, e, fr } = docSnap.data();

  rowEle.insertCell().innerHtml = a;
  rowEle.insertCell().innerHtml = b;
  rowEle.insertCell().innerHtml = c;
  rowEle.insertCell().innerHtml = d;
  rowEle.insertCell().innerHtml = e;
  rowEle.insertCell().innerHtml = fr;
  rowEle.insertCell().innerHtml = '<a href="#">Ver</a> | <a href="#">Edit</a> | <a href="#">Delet</a>';

  // bind the document's ID to the row
  rowEle.dataset.docId = docSnap.id;

  // return the new row element
  return rowEle;
}

现在我们有了一个insert函数,接下来可以创建一个update函数来更新传入的row元素:

function updateRowForDocument(rowEle, docSnap) {
  const { a, b, c, d, e, fr } = docSnap.data();

  rowEle.cells[0].innerHtml = a;
  rowEle.cells[1].innerHtml = b;
  rowEle.cells[2].innerHtml = c;
  rowEle.cells[3].innerHtml = d;
  rowEle.cells[4].innerHtml = e;
  rowEle.cells[5].innerHtml = fr;
  // rowEle.cells[6] won't change
}

不要在renderTable()函数中调用CollectionReference#get,而是从onSnapshot侦听器传入QuerySnapshotQuerySnapshot对象有一个方便的docChanges()方法,该方法提供了一个添加、删除或修改的文档数组(当附加新的侦听器时,所有项的更改类型都将为“added”)。我们可以使用此数组来使用更新的数据高效地刷新表。

**注意:**下一个代码块假设您在<thead>元素中有标题行(否则会出现奇怪的行为)。

function renderTable(qSnap) {
  // get the table and its current rows
  const tableEle = document.getElementById('tabla-datos'),
    tableBodyEle = tBodies[0];
  const rowEleMap = [...tableBodyEle.rows]
    .reduce(
      (idRowMap, rowEle) => idRowMap.set(rowEle.dataset.docId, rowEle),
      new Map()
    );

  // update the rows of each document that changed
  qSnap.docChanges()
    .forEach(({ doc, type }) => {
      // find this document's row (if it exists)
      const rowEle = rowEleMap.get(doc.id);

      if (type === 'removed')
        // row to be removed, remove as needed
        return rowEle && rowEle.remove();
      } else if (!rowEle) {
        // row missing, add it to the table and the map
        return idRowMap.set(doc.id, insertRowForDocument(tableEle, doc));
      }

      // row exists already, update it
      updateRowForDocument(rowEle, doc);
    });

  // [sort rows code here (see below)]

  // Now find the spacing row (if it exists, it doesn't have a `dataset.docId` value)
  let spacingRowEle = rowEleMap.get();
  if (spacingRowEle) {
    // move the spacing row to the bottom of the table
    tableBodyEle.appendChild(spacingRowEle);
  } else {
    // create and append a new spacing row
    spacingRowEle = tableEle.insertRow();
    spacingRowEle.classList.add("space");
  }
}

然后,你在听者的内心这样称呼它:

const unsubscribe = db.collection("Productos")
  .onSnapshot((qSnap) => {
    renderTable(qSnap);
  });

要处理侦听器错误,您需要传入一个observer对象:

const unsubscribe = db.collection("Productos")
  .onSnapshot({
    next(qSnap) {
      renderTable(qSnap);
    },
    error(err) {
      // placeholder logic, update to something more useful
      console.error("Failed to read /Productos: ", err)
    }
  });

一旦上面的代码块被执行,直到你调用unsubscribe(),你的表应该与你的数据库保持同步。对你的文档的任何改变都应该反映在表中。目前,表中的行不会被排序,而是在每个新文档被添加到服务器时被添加。这意味着刷新页面时顺序可能不一样。

**注意:**可能不需要对表中的行进行排序/删除,因为如果将行从光标下方移动,可能会导致用户误单击该行。

当服务器删除文档时,您可以创建一个removeRowForDocument方法,向该行添加一个deleted类,而不是立即删除该行(使其变灰),添加“已在服务器上删除”消息,并将动作链接更新为Restore``Remove(从表中删除行),然后当用户刷新页面或单击“刷新表”按钮时,从表中删除任何已删除的行。
要对表进行排序,可以将以下行插入到renderTable函数中,以便在更新行之后对行进行排序:

**注意:**此排序算法不是最有效的,但在行数较少的情况下运行良好。此排序算法也不处理将行标记为已删除而不是实际从表中删除的情况。

// for each document's row, in the order returned by the query, 
// move it to the end of the table, effectively sorting the table
qSnap.forEach(doc => {
  const rowEle = rowEleMap.get(doc.id);
  rowEle && tableBodyEle.appendChild(rowEle);
})

相关问题