skip to Main Content

I’m creating a project / to-do appliction with firestore.
I want to return all the current projects where the active user has been assigned to.

In a console.log(doc.id, doc.data()), I get the two projects where he has been signed up for.
But when I want to show them both on the home screen, I only see one project.

I don’t know what I’m doing wrong
Anyone that can help me?

My function:

const returnProjects = async () => {
  const list = document.querySelector<HTMLDivElement>('#projectList');
  const projects = query(collectionGroup(db, 'projects'));
  const querySnapshot = await getDocs(projects);
  querySnapshot.forEach((doc) => {
    const deadline = doc.data().Deadline;
    const fireBaseTime = new Date(
      deadline.seconds * 1000 + deadline.nanoseconds / 1000000,
    );
    const formatOptions = {
      format: 'dd MMM  yy', 
    };
    console.log(doc.id, '>', doc.data());
    const newElemement = document.createElement('div');
    if (list) list.appendChild(newElemement).setAttribute('class', 'projectCard');
    const card = document.querySelector<HTMLDivElement>('.projectCard');
    if (card) { card.innerHTML = `
    <h4>${doc.id, doc.data().Name}</h4>
    <p>${fireBaseTime.toLocaleDateString('eng-BE', formatOptions)}</p>
    <span>3</span>
    `; }
  });
};

my Html:

    <main>
      <div id="dashboard" class="dashboard">
        <div class='dashboardUtils'>
          <h3 id="dashboardName"></h3>
          <span id="currentDate"></span>
        </div>
        <button id="editDashboard" class="secondary-button"></button>
      </div>
      <div id='dashboardEdits-form' class="editOpen">
        <form id='dashboardEdits' class='edit-form'>
          <div id='practicalDisplayname'>
            <label for='displayname' class='form-label'>Username</label>
            <input type='text' class='form-input' id="displaynameInput" name='displayname'></input>
          </div>
        </form>
        <button id="confirmEdits" class="secondary-button">Save edits</button>
      </div>
      <div id='amountMessage'>
        <h1 id='amountProjects'></h1>
      </div>
      <div id='projectList'></div>
    </main>

A screenshot:
console.log returns two projects but renders one

2

Answers


  1. The problem is that for each document in the results you do:

    const card = document.querySelector<HTMLDivElement>('.projectCard');
    if (card) { card.innerHTML = `
    <h4>${doc.id, doc.data().Name}</h4>
    <p>${fireBaseTime.toLocaleDateString('eng-BE', formatOptions)}</p>
    <span>3</span>
    `; }
    

    While you’re creating a new project card for each result, the querySelector always returns the first card for the HTML. From the MDN documentation on querySelector:

    An Element object representing the first element in the document that matches

    So for the second document, you’re replacing the innerHTML that you set for the first document.


    To solve the problem, since you already have a reference to the element you just generated, add the innerHTML to that instead of looking it up with a query selector:

    querySnapshot.forEach((doc) => {
      ...
      const newElement = document.createElement('div');
      if (list) list.appendChild(newElemement).setAttribute('class', 'projectCard');
      newElement.innerHTML = `
      <h4>${doc.id, doc.data().Name}</h4>
      <p>${fireBaseTime.toLocaleDateString('eng-BE', formatOptions)}</p>
      <span>3</span>
      `; 
    })
    
    Login or Signup to reply.
  2. The problem you are facing here is caused by the following behavior:

    https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild#:~:text=The%20appendChild()%20method%20of%20the%20Node%20interface%20adds%20a%20node%20to%20the%20end%20of%20the%20list%20of%20children%20of%20a%20specified%20parent%20node.%20If%20the%20given%20child%20is%20a%20reference%20to%20an%20existing%20node%20in%20the%20document%2C%20appendChild()%20moves%20it%20from%20its%20current%20position%20to%20the%20new%20position.

    What this means is that appendChild will remove the node if already present in the DOM, which is what we are seeing here. This can be easily solved by creating a deep clone of the node first using cloneNode, before appending it to the target div.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search