0

This project is a small mobile site. I wanted to serve the HTML for the bibliography dynamically through JS. Here's the code that works perfectly in Firefox:

let butlerBooks = [];
fetch("butler.json").then(res => {
  return res.json();
}).then(loadedButlerBooks => {
    console.log(loadedButlerBooks);
    butlerBooks = loadedButlerBooks;
    loadBooks();
}).catch(err => {
  console.error(err);
});

const biblioItem = document.getElementById('biblioCards');
function loadBooks() {
  butlerBooks.forEach(biblioCard => {
    const biblioContent = `<div id="biblioBorder" class="biblio-card-container">
        <div id="biblioTitle" class="biblio-list-item">
          <div class="biblio-date">${biblioCard.year}</div>
          <div class="biblio-booktitle">${biblioCard.title}</div>
        </div>
        <div id="biblioExpand" class="biblio-card-expand"><img src="./img/expand.png" alt="expand button"></div>
        <div class="biblio-expanded">
          <div class="biblio-expanded-top">
            <div class="biblio-subtitle">${biblioCard.subtitle}</div>
            <div id="biblioMinimize" class="biblio-minimize"><img src="./img/minimize.png" alt="minimize button"></div>
          </div>
          <div id="biblioSubcard" class="biblio-subcard">
            <p class="biblio-booksummary">${biblioCard.summary}</p>
              <a class="biblio-btn-link" href="${biblioCard.url}" target="_blank"><button id="biblioBtn" class="biblio-btn btn" type="button" name="button">View on Goodreads</button>
          </div>
        </div>
      </div>`

  biblioItem.insertAdjacentHTML('afterbegin', biblioContent);

  if (biblioCard.series === "Patternist") {
    console.log('I\'m a Patternist Book!');
    biblioBorder.style.border = "0.2em solid #434463";
    biblioBorder.style.borderLeft = "12px solid #434463";
    biblioBtn.style.backgroundColor = "#434463";
    biblioSubcard.style.background = "rgba(67, 68, 99, 0.3)";
  } else {
    biblioBorder.style.border = "0.2em solid #5EA878";
    biblioBorder.style.borderLeft = "12px solid #5EA878";
    biblioBtn.style.backgroundColor = "#5EA878";
    biblioSubcard.style.background = "rgba(94, 168, 120, 0.3)";
}

This is what the code looks like in Firefox: Bibliography Desired View This is what it looks like in other browsers: Other Browser's Broken view

I get no error messages in Firefox, but the error in Chrome for example is as follows:

TypeError: Cannot set property 'border' of undefined
    at main.js:48
    at Array.forEach (<anonymous>)
    at loadBooks (main.js:25)
    at main.js:18
(anonymous) @ main.js:20
Promise.catch (async)
(anonymous) @ main.js:19

I'm not sure how to fix this. Is it a fetch issue? An id issue? A forEach loop issue? What exactly is preventing the border property from implementing in other browsers? All of the JS I'm using should be supported in most modern browsers (ES6, Arrow Functions, InsertAdjacentHTML, etc) so it's a headscratcher for me.

Thank you in advance for any help!

  • Multiple IDs in a single document is invalid HTML, fix that first. Though, even with duplicate IDs, I'd think Chrome would still see the first element as a global identifier – CertainPerformance May 09 '20 at 16:14
  • I did have a version that used classes only, but I had the exact same problem. Only one card would show up properly on other browsers. I guess I'm trying to figure out how to ensure the for-loop implements on every single instance of a class. – PiggyPandaCub May 09 '20 at 18:51

1 Answers1

0

Figured it out! I had to dynamically assign IDs so that each new HTML instance would be unique. Here's what my project now looks like in Chrome, Firefox, and Safari: All working!

And here's what my code looks like now:

function loadBooks() {
  key = 0;
  for (i = 0; i < butlerBooks.length; i++) {
    key++;
    const biblioContent = `<div id="biblioBorder${key}" class="biblio-card-container">
        <div class="biblio-list-item">
          <div class="biblio-date">${butlerBooks[i].year}</div>
          <div class="biblio-booktitle">${butlerBooks[i].title}</div>
        </div>
        <div  id="expandBtn${key}" class="biblio-card-expand"><img src="./img/expand.png" alt="expand button"></div>
        <div class="biblio-expanded">
          <div id="expandedTop${key}" class="biblio-expanded-top">
            <div class="biblio-subtitle">${butlerBooks[i].subtitle}</div>
            <div id="minimizeBtn${key}" class="biblio-minimize"><img src="./img/minimize.png" alt="minimize button"></div>
          </div>
          <div id="expandedSubcard${key}" class="biblio-subcard">
            <p class="biblio-booksummary">${butlerBooks[i].summary}</p>
              <a class="biblio-btn-link" href="${butlerBooks[i].url}" target="_blank"><button id="btn${key}" class="biblio-btn btn" type="button" name="button">View on Goodreads</button>
          </div>
        </div>
      </div>`

  biblioItem.insertAdjacentHTML('beforeEnd', biblioContent);



const expandedTop = document.getElementById(`expandedTop${key}`);
const expandedSubcard = document.getElementById(`expandedSubcard${key}`);
const expandBtn = document.getElementById(`expandBtn${key}`);
const minimizeBtn = document.getElementById(`minimizeBtn${key}`);

      expandBtn.onclick = () => {
        expandedTop.style.display = "flex";
        expandedSubcard.style.display = "block";
        expandBtn.style.display = "none";
      };

      minimizeBtn.onclick = () => {
        expandedTop.style.display = "none";
        expandedSubcard.style.display = "none";
        expandBtn.style.display = "inline-flex";
      }
   }
};

Thanks to CertainPerformance for your answer! It helped lead me to the question "how do I make IDs unique with Javascript" which ultimately led to the solution.