lundi 3 août 2020

Retrieved firebase object to draw a card with a checkbox, but it draws a new card every time checkbox changes

To learn objects I built this library app where you enter the name of your favorite book and author in a form, and it generates a card with that information.

There's a checkbox on the form to mark if you own it and a "remove" button.

It works with an addtoLibrary() function that takes the info from the form, puts it into an object and that object into firebase.

Within that function, I have another function called render() which takes the info from firebase and puts it into the DOM.

Next I had the app to draw on the DOM every time the app opens so that it brings up all previous entries.

So I built another function called retrievefromDatabase() which also incorporates the render() function, and loops through the list of objects to redraw them.

The problem I'm facing now though is that whenever the checkbox is checked or unchecked, the retrievefromDatabase() function activates and draws another card.

I was running into this problem with my "remove" button, which also changed the state of firebase and drew a new card. To fix this, I changed one call on firebase from .on to .once and that helped.

But the "remove" button is easy because you can't keep changing its state it back and forth.

I could have my retrievefromDatabase() run only once, but then if another user added a card, it would not dynamically update. But it will show when it's reloaded, and I can live with that.

It would be better if retrievefromDatabase() worked like addtoLibrary(), which I can click the checkbox to my heart's delight because it's not reading from firebase, only writing the changes to it.

Accordingly, the new cards are only drawn if they were in the database to begin with. Any new card that's submitted does not have this problem.

So I think my hurdle is I'm not managing firebase well. I spent a week trying to understand how to just CRUD, so obviously I'm no pro!

Can you suggest a solution?

let newPostKey;
let titlesnap;
let fnamesnap;
let lnamesnap;
let pubsnap;
let contribsnap;

function Book(title, fname, lname, pubDate, contrib, own) {
  this.title = title;
  this.fname = fname;
  this.lname = lname;
  this.pubDate = pubDate;
  this.contrib = contrib;
  this.own = own;
};

function retrievefromDatabase() {
  firebase.database().ref("Book").once("value", gotData);
      function gotData(Book) {
      var books = Book.val();
      var keys = Object.keys(books);
        for (var i = 0; i < keys.length; i++) {
          firebase.database().ref("Book/" + keys[i]).on("value", function(snapshot) {
          newPostKey = snapshot.key;    
          function oldBook(title, fname, lname, pubDate, contrib, own) {
            this.title = title;
            this.fname = fname;
            this.lname = lname;
            this.pubDate = pubDate;
            this.contrib = contrib;
            this.own = own;
          };          
          var addBook = new oldBook(snapshot.val().title, 
          snapshot.val().fname, 
          snapshot.val().lname, 
          snapshot.val().pubDate,
          snapshot.val().contrib,
          snapshot.val().own);
          render(oldBook);
        })}}};

retrievefromDatabase();

const submitButton = document.querySelector(".submitButton")
submitButton.addEventListener("click", e => {
  // the prevents the field from clearing on submit
  e.preventDefault();
  addBookToLibrary();
  })

function addBookToLibrary() {
  let title = document.querySelector("#title").value;
  let fname = document.querySelector("#fname").value;
  let lname = document.querySelector("#lname").value;
  let pubDate = document.querySelector("#pubDate").value;
  let contrib = document.querySelector("#contrib").value;
  let own = document.querySelector("#own").checked;
  var addBook = new Book(title, fname, lname, pubDate, contrib, own);
  // I could just put document.querySelector values into var addBook but this is clearer
  newPostKey = firebase.database().ref().child('Book').push().key;
  firebase.database().ref().child('Book').child(newPostKey).set(addBook);
  // console.log(newPostKey);
  // myLibrary.push(addBook);
  render();
  document.querySelector("#title").value = "";
  document.querySelector("#fname").value = "";
  document.querySelector("#lname").value = "";
  document.querySelector("#pubDate").value = "";
  document.querySelector("#contrib").value = "";
  document.querySelector("#own").checked = false;
  // I can also shorten this with form.reset()
  // https://discord.com/channels/505093832157691914/690590001486102589/736653879684628491
};

function render() {
  const bookContainer = document.createElement("div");
  bookContainer.classList.add("book-container");

  const newVolume = document.createElement("div");
  newVolume.classList.add("volume");
  bookContainer.appendChild(newVolume);
  bookContainer.setAttribute('id', `${newPostKey}`);

  const frontCover = document.createElement("div");
  newVolume.appendChild(frontCover);
 
  frontCover.style.setProperty("background-color", getRandomColor());
  
  let TitleRef = firebase.database().ref('Book/' + newPostKey + '/title');
  TitleRef.on('value', function(snapshot) {
  titlesnap = snapshot.val();
  });
// why is this reversed? variable precedes

  let FnameRef = firebase.database().ref('Book/' + newPostKey + '/fname');
  FnameRef.on('value', function(snapshot) {
  fnamesnap = snapshot.val();
  });

  let LnameRef = firebase.database().ref('Book/' + newPostKey + '/lname');
  LnameRef.on('value', function(snapshot) {
  lnamesnap = snapshot.val();
  });

  let pubRef = firebase.database().ref('Book/' + newPostKey + '/pubDate');
  pubRef.on('value', function(snapshot) {
  pubsnap = snapshot.val();
  });

  let contribRef = firebase.database().ref('Book/' + newPostKey + '/contrib');
  contribRef.on('value', function(snapshot) {
  contribsnap = snapshot.val();
  });

  frontCover.innerHTML = "<br /><br />"
                        + "<b>" + titlesnap + "</b>" + "<br /><br />" 
                        + fnamesnap + "&nbsp;"
                        + lnamesnap + "<br /><br />"
                        + "Published: " + pubsnap + "<br />"
                        + "Added by: <br />" + contribsnap + "<br />";
                        
// reads checkbox form, adds it to the rendered volume and interprets value given
  const checkbox = document.createElement('input'); 
  checkbox.type = "checkbox"; 
  checkbox.id = "checkbox"; 

if (document.getElementById("own").checked == true) {
  checkbox.checked = true;
}
else if (document.getElementById("own").checked == true) {
  checkbox.checked = false;
};  

checkbox.addEventListener("change", function() {
if (checkbox.checked === false) {
  firebase.database().ref('Book/' + bookContainer.id + '/own').set(false);
}
else if (checkbox.checked === true) {
  firebase.database().ref('Book/' + bookContainer.id + '/own').set(true);
    }
  });

const label = document.createElement("label"); 
label.appendChild(document.createTextNode(" I own a copy")); 
const newgraf = document.createElement("p")

frontCover.appendChild(checkbox);
frontCover.appendChild(label);
frontCover.appendChild(newgraf);

const removeButton = document.createElement('button')
frontCover.appendChild(removeButton);
removeButton.textContent = 'Remove';
removeButton.addEventListener("click", function(event){
    firebase.database().ref('Book/').child(bookContainer.id).remove()
    bookContainer.remove();
})

libraryContainer.insertAdjacentElement('afterbegin',bookContainer);
};

function getRandomColor() {
  color = "hsl(" + Math.random() * 360 + ", 100%, 20%)";
  return color;
}

If you want to see it in action: https://project-library.acchang.repl.co/




Aucun commentaire:

Enregistrer un commentaire