Search code examples
javascripthtmlfetchappendchild

Shorter method when using append child


I am creating some elements from an object returned via fetch request and wanted to know was there a better method to simplify this?

As it stands it works as expected but it seems ridiculously long for what seems like a simple task?

async function getJobs() {

  const response = await fetch('https://app.beapplied.com/public/all-jobs');
  const data = await response.json();
  console.log(data.jobs);
  for (const job of data.jobs) {
    const jobContainer = document.getElementById("jobData");

    const jobListing = document.createElement('li');
    jobContainer.appendChild(jobListing);
    jobListing.setAttribute('class', 'whr-item')

    const jobLink = document.createElement('a');
    jobListing.appendChild(jobLink);
    jobLink.setAttribute('href', job.applyLink)

    let jobTitle = document.createElement("h3");
    jobTitle.innerHTML = job.title;
    jobTitle.setAttribute('class', 'whr-title')
    jobLink.appendChild(jobTitle);

    const jobInfo = document.createElement('ul');
    jobListing.appendChild(jobInfo);
    jobInfo.setAttribute('class', 'whr-info')

    let jobTeam = document.createElement("li");
    jobTeam.innerHTML = job.team;
    jobTeam.setAttribute('class', 'whr-dept')
    jobInfo.appendChild(jobTeam);

    let jobLocation = document.createElement("li");
    jobLocation.innerHTML = job.location
    jobLocation.setAttribute('class', 'whr-location')
    jobInfo.appendChild(jobLocation);
  }
}

getJobs()
<ul id="jobData" class="whr-items"></ul>


Solution

  • Since you're assigning to the .innerHTML of the nested children, writing out the HTML string and interpolating would be equivalent and a lot more understandable at a glance:

    const jobContainer = document.getElementById("jobData");
    for (const job of data.jobs) {
        jobContainer.insertAdjacentHTML(
            'beforeend',
            `<li class="whr-item">
              <a href="${job.applyLink}">
                <h3>${job.title}</h3>
              </a>
              <ul>
                <li class="whr-dept">${job.team}</li>
                <li class="whr-location">${job.location}</li>
              </ul>
            </li>
            `
        );
    }
    

    That said, interpolating external values directly HTML (or using .innerHTML with external values) is a security risk, since it allows for arbitrary code execution. I'd recommend writing out the HTML without the inserted values, then insert them safely once the structure has been created. For example, you could use createElement for the .whr-item so you have a reference to it, insert its HTML without the dynamic values, then do

    item.querySelector('a').href = job.applyLink;
    item.querySelector('h3').href = job.title;
    item.querySelector('.whr-dept').href = job.team;
    item.querySelector('.whr-location').href = job.location;
    

    This would be a safer approach.