Certain details don't show up right in my online CV

My current project is an online CV where all my credentials - jobs, qualifications, etc. - are printed out with JavaScript (mostly to prove my working JS skills to prospective employers).

I store all my details in objects and among their parameters stored (ie. job title, company, location, date, etc.) are arrays containing bullet points highlight my accomplishments or other important bits.

For example, here is my object constructor for my job entries and a sample object (not) storing records of my career

function Job(title,company,location,date,summary,details) {
  this.title = title;
  this.company = company;
  this.location = location;
  this.date = date;
  this.summary = summary;
  this.details = details;
}

const JOBS = [
  new Job(
    "Office Worker",
    "Some Company I work for",
    "Nowhere in Particular",
    "Never",
    "I am a job description",
    ["Highlighted feat at my job #1",
    "Highlighted feat at my job #2",
    "Highlighted feat at my job #3"]
  )
];

So far, I’m having trouble with this piece in my code.

for (let i=0; i<JOBS.length; i++) {
  const entry = document.createElement("div");
  entry.classList.add("entry");

  const jobContentNarrow = `
          <div class="col-narrow">
            <h3>${JOBS[i].title}</h3>
            <p class="uppercase">${JOBS[i].company}, ${JOBS[i].location}</p>
            <p>${JOBS[i].date}</p>
          </div>
          `;

  const jobContentWide = document.createElement("div");
  jobContentWide.classList.add("col-wide", "description");

  const jobSummary = document.createElement("p");
  jobSummary.innerHTML = `${JOBS[i].summary}`;
  jobContentWide.appendChild(jobSummary);

  const jobDetails = document.createElement("ul");
  for (let e; e<JOBS[i].details.length;e++) {
    const listItem = document.createElement("li");
    listItem.innerHTML = `${JOBS[i].details[e]}`;
    jobDetails.appendChild(listItem);
  };
  jobContentWide.appendChild(jobDetails);
  entry.innerHTML = jobContentNarrow + jobContentWide;

Now’s my current output in HTML when I test it on a web browser

<div class="entry">
     <div class="col-narrow">
         <h3>Digital Media Designer</h3>
         <p class="uppercase">Unit 12, Winchester</p>
         <p>October 2022 ~ Now</p>
     </div>

     // In place of what should be <div class="col-wide description">,
     // this code below happens
     [object HTMLDivElement]
</div>

So what’s the problem?
If you need any further information, I’d be happy to answer.

Thanks.

Can you post a link to your entire code? You seem to be missing part of the code. Your for loop does not have closing }. Also, the full html would be great too.

Oh sorry. You mean the entire for loop or my entire script file?

// Populate the Career section
for (let i=0; i<JOBS.length; i++) {
  const entry = document.createElement("div");
  entry.classList.add("entry");

  const jobContentNarrow = `
          <div class="col-narrow">
            <h3>${JOBS[i].title}</h3>
            <p class="uppercase">${JOBS[i].company}, ${JOBS[i].location}</p>
            <p>${JOBS[i].date}</p>
          </div>
          `;

  const jobContentWide = document.createElement("div");
  jobContentWide.classList.add("col-wide", "description");

  const jobSummary = document.createElement("p");
  jobSummary.innerHTML = `${JOBS[i].summary}`;
  jobContentWide.appendChild(jobSummary);

  const jobDetails = document.createElement("ul");
  for (let e; e<JOBS[i].details.length;e++) {
    const listItem = document.createElement("li");
    listItem.innerHTML = `${JOBS[i].details[e]}`;
    jobDetails.appendChild(listItem);
  };
  jobContentWide.appendChild(jobDetails);
  entry.innerHTML = jobContentNarrow + jobContentWide;
  careerSection.appendChild(entry);
};

Okay, here’s the full script file.

import SKILLS from "./database/skills.js";
import JOBS from "./database/career.js";
import SCHOOLS from "./database/education.js";
import HOBBIES from "./database/hobbies.js";

const body = document.querySelector("body");
const main = document.querySelector("main");
const header = document.querySelector("header");

const warning = document.getElementById("warning");
warning.classList.toggle("display");

// Create the Header
const greeting = {
  name: "James Arrow",
  photo: "media/image/portrait.png",
  alt: "Photo of James Arrow",
  title: "Multimedia + Web Designer",
  description: "Add your profile summary here. You can have several paragraphs or add links.",
  email: "meetme.jw_arrow@erine.email"
};

const profileHead = document.createElement("div");
profileHead.setAttribute("id", "top");
profileHead.classList.add("content-wrap", "clearfix");

const profileImg = document.createElement("img");
profileImg.classList.add("col-narrow");
profileImg.src = greeting.photo;
profileImg.alt = greeting.alt;

const profileBio = document.createElement("div");
profileBio.classList.add("col-wide");

const profileName = document.createElement("h1");
profileName.innerHTML = greeting.name;

const profileTitle = document.createElement("h2");
profileTitle.innerHTML = greeting.title;

const profileDesc = document.createElement("p");
profileDesc.innerHTML = greeting.description;

profileBio.appendChild(profileName);
profileBio.appendChild(profileTitle);
profileBio.appendChild(profileDesc);

profileHead.appendChild(profileImg);
profileHead.appendChild(profileBio);
header.appendChild(profileHead);

// Create the top navbar

// Perhaps I'll expand the array below into a collection of objects
// or arrays containin the links and their relevant details
// i.e. fontawesome icons, etc.

const navItems = ["Skills", "Career", "Education", "Hobbies", "Contact"];
const topNav = document.createElement("nav");
topNav.setAttribute("role", "navigation");
topNav.classList.add("nav-max");
const topNavList = document.createElement("ul");
topNavList.classList.add("navbar");

// Populate the navbar
for (let i = 0; i < navItems.length; i++) {
  let item = document.createElement("li");
  let itemLink = document.createElement("a");
  let itemIcon = document.createElement("i");
  let description;
  itemIcon.classList.add("fas");
  switch (true) {
    case navItems[i] === "Skills":
      itemLink.href = "#skills";
      itemIcon.classList.add("fa-star");
      description = "Skills";
      break;
    case navItems[i] === "Career":
      itemLink.href = "#career";
      itemIcon.classList.add("fa-briefcase");
      description = "Career";
      break;
    case navItems[i] === "Education":
      itemLink.href = "#education";
      itemIcon.classList.add("fa-graduation-cap");
      description = "Education";
      break;
    case navItems[i] === "Hobbies":
      itemLink.href = "#hobbies";
      itemIcon.classList.add("fa-heart");
      description = "Hobbies";
      break;
    case navItems[i] === "Contact":
      itemLink.href = "#contact";
      itemIcon.classList.add("fa-address-book");
      description = "Contact";
      break;
  }
  let itemText = document.createTextNode(description);
  itemLink.appendChild(itemIcon);
  itemLink.appendChild(itemText);
  item.appendChild(itemLink);
  topNavList.append(item);
}
// Append the links to the top navbar
topNav.appendChild(topNavList);
main.appendChild(topNav);

// Create the Skills section
const skillsSection = document.createElement("section");
skillsSection.setAttribute("id", "skills");
skillsSection.classList.add("content-wrap", "clearfix");

const skillsHeading = document.createElement("h2");
skillsHeading.innerHTML = `<i class="fas fa-star"></i>Skills`;
skillsSection.appendChild(skillsHeading);
main.appendChild(skillsSection);

// Populate the Skills section
for (let i=0; i<SKILLS.length; i++) {
  const entry = document.createElement("div");
  entry.classList.add("entry");

  const skillType = document.createElement("div");
  skillType.classList.add("col-skill");
  skillType.innerHTML = `<h3><i class=${SKILLS[i].icon}></i> ${SKILLS[i].title}</h3>`;

  for (let e=0; e<SKILLS[i].skills.length;e++) {

  }

  entry.appendChild(skillType);
  skillsSection.appendChild(entry);
};

// Create the Career section
const careerSection = document.createElement("section");
careerSection.setAttribute("id", "career");
careerSection.classList.add("content-wrap", "clearfix");

const careerHeading = document.createElement("h2");
careerHeading.innerHTML = `<i class="fas fa-briefcase"></i>Career`;
careerSection.appendChild(careerHeading);
main.appendChild(careerSection);

// Populate the Career section
for (let i=0; i<JOBS.length; i++) {
  const entry = document.createElement("div");
  entry.classList.add("entry");

  const jobContentNarrow = `
          <div class="col-narrow">
            <h3>${JOBS[i].title}</h3>
            <p class="uppercase">${JOBS[i].company}, ${JOBS[i].location}</p>
            <p>${JOBS[i].date}</p>
          </div>
          `;

  const jobContentWide = document.createElement("div");
  jobContentWide.classList.add("col-wide", "description");

  const jobSummary = document.createElement("p");
  jobSummary.innerHTML = `${JOBS[i].summary}`;
  jobContentWide.appendChild(jobSummary);

  const jobDetails = document.createElement("ul");
  for (let e; e<JOBS[i].details.length;e++) {
    const listItem = document.createElement("li");
    listItem.innerHTML = `${JOBS[i].details[e]}`;
    jobDetails.appendChild(listItem);
  };
  jobContentWide.appendChild(jobDetails);
  entry.innerHTML = jobContentNarrow + jobContentWide;

  // const jobContent = `
  //         <div class="col-narrow">
  //           <h3>${JOBS[i].title}</h3>
  //           <p class="uppercase">${JOBS[i].company}, ${JOBS[i].location}</p>
  //           <p>${JOBS[i].date}</p>
  //         </div>
  //         <div class="col-wide description">
  //           <p>${JOBS[i].summary}</p>
  //           <ul>
  //             <li>${JOBS[i].details[0]}</li>
  //             <li>${JOBS[i].details[1]}</li>
  //             <li>${JOBS[i].details[2]}</li>
  //           </ul>
  //         </div>
  //         `;

  // entry.innerHTML = jobContent;
  careerSection.appendChild(entry);
};


// Create the Education section
const educateSection = document.createElement("section");
educateSection.setAttribute("id", "education");
educateSection.classList.add("content-wrap", "clearfix");

const educateHeading = document.createElement("h2");
educateHeading.innerHTML = `<i class="fas fa-graduation-cap"></i>Education`;
educateSection.appendChild(educateHeading);
main.appendChild(educateSection);

// Populate the Education section
for (let i=0; i<SCHOOLS.length; i++) {
  const entry = document.createElement("div");
  entry.classList.add("entry");

  const schoolContent = `
          <div class="col-narrow">
            <h3>${SCHOOLS[i].location}</h3>
          </div>
          <div class="col-wide description">
          <p class="uppercase">${SCHOOLS[i].course}, ${SCHOOLS[i].date}</p>
          <p>${SCHOOLS[i].degree}, ${SCHOOLS[i].qualification}</p>
          </div>
          `;

  entry.innerHTML = schoolContent;
  educateSection.appendChild(entry);
};

// Create the Hobbies section
const hobbySection = document.createElement("section");
hobbySection.setAttribute("id", "hobbies");
hobbySection.classList.add("content-wrap", "clearfix");

const hobbyHeading = document.createElement("h2");
hobbyHeading.innerHTML = `<i class="fas fa-heart"></i>Hobbies`;
hobbySection.appendChild(hobbyHeading);
main.appendChild(hobbySection);

// Create the bottom navbar
const bottomNav = document.createElement("nav");
bottomNav.setAttribute("role", "navigation");
bottomNav.classList.add("nav-min");
const bottomNavList = document.createElement("ul");
bottomNavList.classList.add("navbar");

// Populate the navbar
for (let i = 0; i < navItems.length; i++) {
  let item = document.createElement("li");
  let itemLink = document.createElement("a");
  let itemIcon = document.createElement("i");
  itemIcon.setAttribute("aria-hidden", true);
  let itemSpan = document.createElement("span");
  itemIcon.classList.add("fas");
  switch (true) {
    case navItems[i] === "Skills":
      itemLink.href = "#skills";
      itemIcon.classList.add("fa-star", "fa-2x");
      itemSpan.innerHTML = "Skills";
      break;
    case navItems[i] === "Career":
      itemLink.href = "#career";
      itemIcon.classList.add("fa-briefcase", "fa-2x");
      itemSpan.innerHTML = "Career";
      break;
    case navItems[i] === "Education":
      itemLink.href = "#education";
      itemIcon.classList.add("fa-graduation-cap", "fa-2x");
      itemSpan.innerHTML = "Education";
      break;
    case navItems[i] === "Hobbies":
      itemLink.href = "#hobbies";
      itemIcon.classList.add("fa-heart", "fa-2x");
      itemSpan.innerHTML = "Hobbies";
      break;
    case navItems[i] === "Contact":
      itemLink.href = "#contact";
      itemIcon.classList.add("fa-address-book", "fa-2x");
      itemSpan.innerHTML = "Contact";
      break;
  }
  itemSpan.classList.add("sr-only");
  itemLink.appendChild(itemIcon);
  itemLink.appendChild(itemSpan);
  item.appendChild(itemLink);
  bottomNavList.append(item);
}
// Append the links to the top navbar
bottomNav.appendChild(bottomNavList);
main.appendChild(bottomNav);


// Create the footer
const footer = document.createElement("footer");
footer.classList.add("content-wrap", "clearfix");
footer.setAttribute("role", "contact");
footer.setAttribute("id", "contact");

const footerTitle = document.createElement("h2");
footerTitle.innerHTML = `<i class="fas fa-paper-plane"></i>Let's Keep in Touch!`;

// An object full of objects or arrays containing my contact details
// and social media links
// const contactDetails = {
//   email
// }

const email = document.createElement("a");
email.href = `mailto:${greeting.email}`;
email.innerHTML = `<i class="fas fa-2x fa-envelope" aria-hidden="true"></i><span class="sr-only">Send an Email to James Arrow</span>`;

const year = new Date();
const copyright = document.createElement("p");
copyright.innerHTML = `&copy; ${year.getFullYear()} James Arrow`;

const backToTop = document.createElement("a");
backToTop.href = "#top";
backToTop.innerHTML = `<i class="fas fa-arrow-circle-up"></i>Back to Top`

footer.appendChild(footerTitle);
footer.appendChild(email);
footer.appendChild(copyright);
footer.appendChild(backToTop);
body.appendChild(footer);

And here’s the HTML output

<html lang="en">

<head>
  <script src="https://kit.fontawesome.com/6465a72a1f.js" crossorigin="anonymous"></script>

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>James Arrow | Multimedia + Web Designer</title>
  <link rel="stylesheet" href="style.css">
  <script type="module" src="js/script.js" defer=""></script>
</head>

<body>
  <!--  Intro -->
  <header role="banner" class="content-wrap clearfix">
    <div id="warning" class="display">
      <h1>WARNING!</h1>
      <h2>You have JavaScript turned off!</h2>
      <p>Please turn it back on to view this website <br>
        Or visit the <a href="#">Non-JS version here</a><br><br>
        <em>Don't worry. I am definitely spying on you. ^^</em>
      </p>
    </div>
    <div id="top" class="content-wrap clearfix"><img class="col-narrow" src="media/image/portrait.png" alt="Photo of James Arrow">
      <div class="col-wide">
        <h1>James Arrow</h1>
        <h2>Multimedia + Web Designer</h2>
        <p>Add your profile summary here. You can have several paragraphs or add links.</p>
      </div>
    </div>
  </header>

  <main role="main">
    <nav role="navigation" class="nav-max">
      <ul class="navbar">
        <li><a href="#skills"><i class="fas fa-star"></i>Skills</a></li>
        <li><a href="#career"><i class="fas fa-briefcase"></i>Career</a></li>
        <li><a href="#education"><i class="fas fa-graduation-cap"></i>Education</a></li>
        <li><a href="#hobbies"><i class="fas fa-heart"></i>Hobbies</a></li>
        <li><a href="#contact"><i class="fas fa-address-book"></i>Contact</a></li>
      </ul>
    </nav>
    <section id="skills" class="content-wrap clearfix">
      <h2><i class="fas fa-star"></i>Skills</h2>
      <div class="entry">
        <div class="col-skill">
          <h3><i class="fa-solid" fa-computer=""></i> Operating Systems</h3>
        </div>
      </div>
      <div class="entry">
        <div class="col-skill">
          <h3><i class="fa-solid" fa-code=""></i> Coding</h3>
        </div>
      </div>
      <div class="entry">
        <div class="col-skill">
          <h3><i class="fa-solid" fa-palette=""></i> Graphic Design</h3>
        </div>
      </div>
      <div class="entry">
        <div class="col-skill">
          <h3><i class="fa-solid" fa-palette=""></i> Video Production</h3>
        </div>
      </div>
    </section>
    <section id="career" class="content-wrap clearfix">
      <h2><i class="fas fa-briefcase"></i>Career</h2>
      <div class="entry">
        <div class="col-narrow">
          <h3>Digital Media Designer</h3>
          <p class="uppercase">Unit 12, Winchester</p>
          <p>October 2022 ~ Now</p>
        </div>
        [object HTMLDivElement]
      </div>
    </section>
    <section id="education" class="content-wrap clearfix">
      <h2><i class="fas fa-graduation-cap"></i>Education</h2>
      <div class="entry">
        <div class="col-narrow">
          <h3>Portsmouth University</h3>
        </div>
        <div class="col-wide description">
          <p class="uppercase">MSc Digital Media, 2018</p>
          <p>Masters Degree, Merit</p>
        </div>
      </div>
      <div class="entry">
        <div class="col-narrow">
          <h3>Southampton Solent University</h3>
        </div>
        <div class="col-wide description">
          <p class="uppercase">BA (Hons) Animation, 2015</p>
          <p>Bachelor's Degree, 1st Class Honours</p>
        </div>
      </div>
    </section>
    <section id="hobbies" class="content-wrap clearfix">
      <h2><i class="fas fa-heart"></i>Hobbies</h2>
    </section>
    <nav role="navigation" class="nav-min">
      <ul class="navbar">
        <li><a href="#skills"><i aria-hidden="true" class="fas fa-star fa-2x"></i><span class="sr-only">Skills</span></a></li>
        <li><a href="#career"><i aria-hidden="true" class="fas fa-briefcase fa-2x"></i><span class="sr-only">Career</span></a></li>
        <li><a href="#education"><i aria-hidden="true" class="fas fa-graduation-cap fa-2x"></i><span class="sr-only">Education</span></a></li>
        <li><a href="#hobbies"><i aria-hidden="true" class="fas fa-heart fa-2x"></i><span class="sr-only">Hobbies</span></a></li>
        <li><a href="#contact"><i aria-hidden="true" class="fas fa-address-book fa-2x"></i><span class="sr-only">Contact</span></a></li>
      </ul>
    </nav>
  </main>
  <!-- Code injected by live-server -->
  <script type="text/javascript">
    // <![CDATA[  <-- For SVG support
    if ('WebSocket' in window) {
      (function() {
        function refreshCSS() {
          var sheets = [].slice.call(document.getElementsByTagName("link"));
          var head = document.getElementsByTagName("head")[0];
          for (var i = 0; i < sheets.length; ++i) {
            var elem = sheets[i];
            head.removeChild(elem);
            var rel = elem.rel;
            if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
              var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
              elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
            }
            head.appendChild(elem);
          }
        }
        var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
        var address = protocol + window.location.host + window.location.pathname + '/ws';
        var socket = new WebSocket(address);
        socket.onmessage = function(msg) {
          if (msg.data == 'reload') window.location.reload();
          else if (msg.data == 'refreshcss') refreshCSS();
        };
        console.log('Live reload enabled.');
      })();
    }
    // ]]>
  </script>


  <footer class="content-wrap clearfix" role="contact" id="contact">
    <h2><i class="fas fa-paper-plane"></i>Let's Keep in Touch!</h2><a href="mailto:meetme.jw_arrow@erine.email"><i class="fas fa-2x fa-envelope" aria-hidden="true"></i><span class="sr-only">Send an Email to James Arrow</span></a>
    <p>© 2022 James Arrow</p><a href="#top"><i class="fas fa-arrow-circle-up"></i>Back to Top</a>
  </footer>
</body>

</html>

You are trying to concatenate a string of html (jobContentNarrow) with an actual element (jobContentWide). That will result in what you are seeing here.

FYI - This is not a good use of switch. I would definitely look into adding this stuff in your navItems array (as your code comment mentions).

1 Like

I see.

Well, I changed

entry.innerHTML = jobContentNarrow + jobContentWide;

into

entry.appendChild(jobContentNarrow);
entry.appendChild(jobContentWide);

But now I find my career section empty and I got
this error message in the browser console

script.js:173 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
    at script.js:173:9

Yes, that is because in your line entry.appendChild(jobContentNarrow); the appendChild method is expecting a node and not a string which jobContentNarrow is.

1 Like

So basically, when I use appendChild, I strictly use it to append elements
and innerHTML to concatenate strings?

Why not do something similar for jobContentWide what you did for jobContentNarrow?

Because each of the details arrays for my jobs may have different amounts of items I want to include so I made a for loop to add <li> elements for every one then add it to jobContentWide.

Hence

const jobDetails = document.createElement("ul");
  for (let e; e < JOBS[i].details.length; e++) {
    const listItem = document.createElement("li");
    listItem.innerHTML = `${JOBS[i].details[e]}`;
    jobDetails.appendChild(listItem);
  };
  jobContentWide.appendChild(jobDetails);

I can’t do that with a string literal by itself, can I?

However, even with this code I got the same problem I had before with
[object HTMLDivElement] showing up instead of proper HTML.

Sure you can. You can create a variable named jobDetails that you will hold all the li elements and their content and then inside the ul element string (of the template literal you would have a line like:

<ul>
  ${jobDetails}
</ul>

I beg your pardon?
How? You lost me.

I mean I get I can do this
const jobDetails = JOBS[i].details

But how do I put each of the array items into li elements with a template literal and not a for loop?

You can initialize jobDetails as a string and the iterate through your for loop with something like:

jobDetails += `<li>${JOBS[i].details}</li>`;
1 Like

Good news. I just incorporated the changes you suggested and now everything’s showing properly.

Thanks.