# #javascript #firebase #google-cloud-firestore
Вопрос:
Я пытаюсь изучить JavaScript, и он используется в некоторых базовых веб-технологиях. Я следую фантастической серии NetNinja для создания базового приложения Google Firebase — Firestore. Большая часть кода ниже взята из класса, однако я пытаюсь добавить функцию для обновления логического поля после щелчка по элементу li (см. строку 26 — app.js). Обновление переключает значение логического значения.
Я испытываю проблему, когда элемент li дублируется и появляется дважды в списке, когда я обновляю браузер, дублированный элемент li исчезает. Значение поля обновляется в firestore правильно, и я могу видеть изменения в firestore — я просто не уверен в своей реализации функции db.collection().doc().update ().
Примечание — в настоящее время я только открываю index.html файл локально, в Chrome (но я не думаю, что это вызывает эту проблему). Я пытался выполнить обновление непосредственно в консоли, но, похоже, у меня такое же поведение, что заставляет меня думать, что это моя реализация функции обновления.
Любая помощь будет очень признательна, наряду с улучшениями и объяснениями. Заранее большое спасибо!
index.html
<html>
<head>
<link rel="stylesheet" href="styles.css">
<script src="https://www.gstatic.com/firebasejs/8.7.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.7.0/firebase-firestore.js"></script>
</head>
<body>
<h1>Bob Things</h1>
<div class="content">
<form id="add-item-form">
<input type="text" name="item" placeholder="Bob item">
<input type="text" name="replenish" placeholder="true">
<button>Add Item</button>
</form>
<ul id="item-list"></ul>
</div>
<script>
// Initialise Firebase
var firebaseConfig = {
apiKey: "AIzaSyDccrM8EErMCUUc4XUdkEytPDwUuJryxrA",
authDomain: "firestore-test-5b316.firebaseapp.com",
projectId: "firestore-test-5b316",
storageBucket: "firestore-test-5b316.appspot.com",
messagingSenderId: "588262547847",
appId: "1:588262547847:web:3bf82908cce90ec8e3f322"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
db.settings({ timestampsInSnapshots:true ,merge:true});
</script>
<script src="app.js"></script>
</body>
</html>
app.js
const itemList = document.querySelector('#item-list');
const form = document.querySelector('#add-item-form');
const collectionVal = "bob_things"
// Create element and render info
function renderItems(doc){
// Set variables and setup li elements
let li = document.createElement('li');
let item = document.createElement('span');
let replenish = document.createElement('span');
let cross = document.createElement('div');
li.setAttribute('data-id',doc.id);
item.textContent = doc.data().item;
replenish.textContent = doc.data().replenish;
cross.textContent = 'x';
// Add to main li
li.appendChild(item);
li.appendChild(replenish);
li.appendChild(cross);
itemList.appendChild(li);
// Onclick should change
li.addEventListener('click',(e)=>{
console.log('here');
let id = e.target.parentElement.getAttribute('data-id');
let replenishNewVal = !doc.data().replenish;
db.collection(collectionVal).doc(id).update({
replenish: replenishNewVal
})
.then(() =>{
console.log('Updated ' doc.data().item);
})
.catch((error)=> {
console.error('Error updating',error);
})
})
// Deleting a list item
cross.addEventListener('click',(e)=>{
e.stopPropagation();
let id = e.target.parentElement.getAttribute('data-id');
db.collection(collectionVal).doc(id).delete();
})
}
// Saving Data
form.addEventListener('submit',(e) => {
e.preventDefault();
db.collection(collectionVal).add({
item: form.item.value,
replenish: form.replenish.value
})
form.item.value = '';
form.replenish.value = '';
})
// Realtime listener
db.collection(collectionVal).onSnapshot(snapshot => {
console.log('ran the listener');
let changes = snapshot.docChanges();
changes.forEach(change => {
if (change.type == 'added' || change.type == 'modified'){
renderItems(change.doc);
} else if (change.type == 'removed'){
let li = itemList.querySelector('[data-id=' change.doc.id ']');
itemList.removeChild(li);
}
})
})
Комментарии:
1. Когда вы говорите, что «открываете index.html файл локально», вы имеете в виду, что используете локальный веб-сервер? Или вы имеете в виду, что просто открываете файл по
file://
протоколу? Они очень разные.
Ответ №1:
Проблема в том, что здесь:
db.collection(collectionVal).onSnapshot(snapshot => {
console.log('ran the listener');
let changes = snapshot.docChanges();
changes.forEach(change => {
if (change.type == 'added' || change.type == 'modified'){ // 👈 For new or updated item
renderItems(change.doc); // 👈 add a new LI item to the HTML
} else if (change.type == 'removed'){
let li = itemList.querySelector('[data-id=' change.doc.id ']');
itemList.removeChild(li);
}
})
})
Поэтому для каждого нового или обновленного элемента вы добавляете новый LI в HTML. Но когда документ обновляется в базе данных, вы должны фактически обновить соответствующий LI в HTML вместо создания нового.
Самое простое исправление, основанное на вашем существующем коде,-это удалить LI, а затем повторно добавить его:
if (change.type == 'removed' || change.type == 'modified'){
let li = itemList.querySelector('[data-id=' change.doc.id ']');
itemList.removeChild(li);
}
if (change.type == 'added' || change.type == 'modified'){
renderItems(change.doc);
}
Так что теперь modified
обрабатывается дважды: один раз, чтобы удалить существующий LI, и один раз, чтобы добавить новый.
Хотя все вышесказанное работает, лучшим решением было бы найти существующий файл LI в HTML, а затем обновить его данными из измененного документа. Я рекомендую попробовать это самостоятельно, так как это даст вам более идиоматичное решение.
Комментарии:
1. Большое спасибо Фрэнку — это помогло! Большое спасибо за четко объясненный ответ.