Stop rogue backtick from getting rendered

Hello Everyone,

First post here, I hope I’ll be doing everything right.

I managed to get this function to work but there’s an unwanted backtick that gets rendered along with the rest. Could someone help me to get rid of it so the function still works? It’s the one between the colon and the opening <p> tag in the inner .map(). I suspect I’m abusing template literals a bit.

function buildOutput(obj) {
  const marksheet = document.querySelector('.marksheet');

  marksheet.innerHTML =
    `
      <h1>${obj.testName}</h1>
      <h1>${obj.date} – ${obj.class}</h1>
      <h2 class="block">${obj.studentName} – TOTAL: <span class="scores">${obj.totalScore} / ${obj.maxScore}</span></h2>

      ${Object.values(obj.testStructure)
      .map(val =>
        `
            <h3 class="block">PART ${val.partNumber} ${val.taskType} <span class="scores">${val.partScore}</span></h3>

            ${Object.values(val.questions)
          .map(qn =>
            val.partNumber === 4 && val.taskType === 'Key word transformation'
              ? `<p>
                  <span class="qn-number">${qn.questionNumber}</span>
                  <button class="button btn-incorrect">0</button>
                  <button class="button btn-one">1</button>
                  <button class="button btn-two">2</button>
                  <span class="scores">${qn.score === null ? `&#9650` : qn.score}</span>
                    </p>`
              :
              `<p>
                  <span class="qn-number">${qn.questionNumber}</span>
                  <button class="button btn-incorrect">X</button>
                  <button class="button btn-correct">&#10003</button>
                  <span class="scores">${qn.score === null ? `&#9650` : qn.score}</span>
                  </p>`
          )
        }
          `
      )
    }
    `
};

Which framework is being used there?

It’s not,Paul, he’s just using a very large code block in the middle of a template literal that’s using other template literals…

First of all, welcome to Sitepoint Forums, @leventemo. You’ve already learned to put code in codeblocks, which is definitely doing things right! :wink:

I’m not sure it’s proper to return an array from the inner function, tbh… but thats neither here nor there at the moment…

I’ll have to have a play with this to see what it’s doing and why it’s going wrong, but my first instinct is it’s because you’ve put the <backtick><P> on a separate line from the colon…

Okay, so… I ran your code. (https://codepen.io/EtoileLion/pen/xxqOpLP, if you care).
I don’t get errant backticks. What i get are errant commas, which are because you’re returning an array with .map(), which when stringified by default will return a string with commas between elements.

You can eliminate the commas by adding .join("") after the closing ) of the map calls (both of them!) (https://codepen.io/EtoileLion/pen/OJpXzQK); this is you jumping ahead of the stringifier by saying “no i want my array to be a string with no delimiter.”

2 Likes

Well, thanks m_hutley and Paul for saving me from hours of head-banging. The commas are gone now, of course. It all says a lot about my eye-sight, as well as my inexperience. I remember the fleeting moment when I thought they might actually be commas but as I was having a hard-enough time with all the nested-type template literals I decided they couldn’t be anything else than backticks.
I’d like to know how the function itself should be built properly but that should go into a different topic/thread I guess. Thanks again,

Levente

With a bit of a delay, here is a rewrite of the buildOutput function. It seems to work fine:

function buildOutput(obj) {
  const marksheet = document.querySelector('.marksheet');

  function buildTestHeader(obj) {
    const { testName, date, group, studentName, totalScore, maxScore } = obj;

    return `
      <h1>${testName}</h1>
      <h1>${date} – ${group}</h1>
      <h2 class="block">${studentName} – TOTAL: <span class="scores">${totalScore} / ${maxScore}</span></h2>
    `
  }

  function buildTestBody(obj) {
    let string = '';

    obj.testStructure.forEach(part => {
      const { partNumber, taskType, partScore, questions } = part;

      string += `<h3 class="block">PART ${partNumber} ${taskType} <span class="scores">${partScore}</span></h3>`

      if (partNumber === 4 && taskType === 'Key word transformation') {
        questions.forEach(question => {
          const { questionNumber, score } = question;

          string += `
            <p>
              <span class="qn-number">${questionNumber}</span>
              <button class="button btn-incorrect">0</button>
              <button class="button btn-one">1</button>
              <button class="button btn-two">2</button>
              <span class="scores">${score === null ? `&#9650` : score}</span>
            </p>`
        })
      } else {
        questions.forEach(question => {
          const { questionNumber, score } = question;

          string += `
            <p>
              <span class="qn-number">${questionNumber}</span>
              <button class="button btn-incorrect">X</button>
              <button class="button btn-correct">&#10003</button>
              <span class="scores">${score === null ? `&#9650` : score}</span>
            </p>`
        })
      }
    });
    return string;
  }

  const header = buildTestHeader(obj);
  const body = buildTestBody(obj);

  marksheet.innerHTML = `${header} ${body}`;
};

what I’ve done:

  • I replaced the map() methods with forEach
  • I’ve broken up the lengthy template literals into two parts, testHeader and testBody
  • I didn’t break up the rendering of testStructure (the nested part of the object) because I need the order of questions as it is

Is the use of forEach() legit here? I mean, I’m just writing a string but I’m not changing the state object when I’m doing that, right?
Any other suggestions for improvement would be most welcome.
Thanks

Levente

This isnt an ‘improvement’ so much as it is personal choice, but i’d just do
marksheet.innerHTML = header+body;
Not really a need for the space between the two.

I also question this logic.

Why does this type of output only pertain to partNumber 4? Should not all output of the type Key word transformation have the same output?

if (partNumber === 4 && taskType === 'Key word transformation') {
Well-spotted. It’s just extra caution there for now as there are a few more templates to be typed up and in theory there might be a case of Key word transformation going “else” rather than “if”.

Yes, I think I’m with you on marksheet.innerHTML ={header} {body}; too.

Thanks

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.