A report table

Build a complete table from data, including data that tries to be HTML.

What to build

A table with a heading row, one row per student and a footer showing the average.

Requirements

  • Inside #report, make a thead with two th cells: Name and Mark.
  • Make a tbody with one tr per student, each with two td cells. Give the row the class top if the mark is 80 or more.
  • Make a tfoot with one row: a td with Average, and a td with the average mark to 1 decimal place.
  • One student's name contains HTML tags. It must appear on the page as those exact characters, and must not become an element.

Constraints

Do not write any rows in the HTML, and do not use innerHTML.

Example

The footer shows Average and 70.0.

Why it works

The third name is a small example of what an attacker could type. Because textContent never reads text as HTML, the tags are displayed harmlessly, and no extra checking is needed.

Hints

Hint 1

A small helper that makes a cell with some text saves a lot of repetition.

Hint 2

Append rows to a tbody, and put the headings in a thead.

Hint 3

Setting textContent means the name with tags in it stays harmless text.

Solution

Show one correct solution (try it yourself first)
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Report</title>
  <style>
    .top { background: gold; }
  </style>
</head>
<body>
  <table id="report"></table>
  <script>
    const students = [
      { name: "Rahim", mark: 82 },
      { name: "Mitu", mark: 91 },
      { name: "<b>Arif</b>", mark: 67 },
      { name: "Sadia", mark: 40 },
    ];
    const table = document.querySelector("#report");

    function cell(tag, text) {
      const el = document.createElement(tag);
      el.textContent = text;
      return el;
    }

    function row(...cells) {
      const tr = document.createElement("tr");
      tr.append(...cells);
      return tr;
    }

    const head = document.createElement("thead");
    head.append(row(cell("th", "Name"), cell("th", "Mark")));

    const body = document.createElement("tbody");
    for (const student of students) {
      const tr = row(cell("td", student.name), cell("td", student.mark));
      if (student.mark >= 80) tr.classList.add("top");
      body.append(tr);
    }

    const total = students.reduce((sum, s) => sum + s.mark, 0);
    const foot = document.createElement("tfoot");
    foot.append(row(cell("td", "Average"), cell("td", (total / students.length).toFixed(1))));

    table.append(head, body, foot);
  </script>
</body>
</html>

Lesson: The DOM: changing the page with JavaScript →