1

I am building a futures market data table for my client using an external API, JavaScript and HTML. The data from the JSON response will need to be outputted into a table that matches the following screenshot.

Data table example

The dynamic data in the table will need to be loaded in two parts, with a static part in between. A code example is below. The HTML details how it should look, but the JavaScript is what I currently have working. I have attached a second screenshot showing the current output I have locally on my computer.

Current HTML table output

How can I adjust my JavaScript and HTML code to display the dynamic commodity name and symbol with the static column headings below, then dynamic data rows below that.

I am using vanilla JS and do not want any jQuery solutions. Thanks.

const futures = (() => {
  const futuresTable = document.querySelector("[data-futures]");

  // Bail if data-futures attribute does not exist in DOM
  if (!futuresTable) {
    return;
  }

  const fetchData = () => {
    const apiKey = "";
    const request = `https://api.dtn.com/markets/symbols/%40S%60%23%23%203%2C%40C%60%23%23%203%2C%40W%60%23%23%203/quotes?priceFormat=decimal&type=A&symbolLimit=10&apikey=${apiKey}`;

    fetch(request)
      .then(response => response.json())
      .then((data) => displayData(data))
      .catch(error => {
        console.log(error);
      });
  }
  fetchData();

  const displayData = (data) => {
    // marketsFeed.classList.add("loaded");
    const commodities = data;

    const locale = 'en-CA';
    const dateOptions = {
      month: 'long',
      year: 'numeric',
    };

    for (let commodity of commodities) {
      console.log(commodity);
      let name = commodity.userDescription;
      let month = new Date(commodity.contractDate).toLocaleDateString("en-CA", {
        year: 'numeric',
        month: 'long'
      });
      let description = commodity.symbol.description;
      let symbol = commodity.actualSymbol;
      let last = commodity.last.number;
      let change = commodity.change.number;
      let high = commodity.high.number;
      let low = commodity.low.number;
      let settleDate = new Date(commodity.settleDate).toLocaleDateString("en-CA", {
        year: 'numeric',
        month: 'long',
        day: '2-digit'
      });
      let settlePrice = commodity.settlePrice.number;
      dataTable(name, month, description, symbol, last, change, high, low, settleDate, settlePrice);
    }
  }

  const dataTable = (name, month, description, symbol, last, change, high, low, settleDate, settlePrice) => {
    const dataRow = `
      <thead>
        <tr>
          <th colspan="9">${name}</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>Month</th>
          <th>Symbol</th>
          <th>Last</th>
          <th>Change</th>
          <th>High</th>
          <th>Low</th>
          <th>Settle Date</th>
          <th>Settle Price</th>
          <th>More</th>
        </tr>
        <tr>
          <td>${month}</td>
          <td>${symbol}</td>
          <td>${last}</td>
          <td>${change}</td>
          <td>${high}</td>
          <td>${low}</td>
          <td>${settleDate}</td>
          <td>${settlePrice}</td>
        </tr>
      </tbody>
    `;
    futuresTable.insertAdjacentHTML("beforeend", dataRow);
  }
})();
table {
  border-collapse: collapse;
  border: 1px solid #ccc;
  font-family: sans-serif;
}

table th,
table td {
  padding: 0.5rem;
  border: 1px solid #ccc;
}

table th {
  text-align: left;
}
<table data-futures>
  <tbody>
    <tr>
      <th colspan="9">
        <!-- Dynamic HTML table content -->
        <!-- commodity is returned from the JSON fetch response -->
        ${commodity.userDescription}<span>${commodity.symbol}</span>
      </th>
    </tr>
    <tr>
      <!-- Static HTML table content -->
      <th scope="col">Month</th>
      <th scope="col">Last</th>
      <th scope="col">Change</th>
      <th scope="col">High</th>
      <th scope="col">Low</th>
      <th scope="col">Settle Date</th>
      <th scope="col">Settle Price</th>
      <th scope="col">More</th>
    </tr>
    <tr>
      <!-- Dynamic HTML table content -->
      <td>August 2022</td>
      <td>1265'2</td>
      <td>-2'4</td>
      <td>1275'2</td>
      <td>1261'4</td>
      <td>October 27, 2021</td>
      <td>1265'2</td>
      <td>Icon</td>
    </tr>
    <tr>
      <!-- Dynamic HTML table content -->
      <td>August 2022</td>
      <td>1265'2</td>
      <td>-2'4</td>
      <td>1275'2</td>
      <td>1261'4</td>
      <td>October 27, 2021</td>
      <td>1265'2</td>
      <td>Icon</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th colspan="9">
        <!-- Dynamic HTML table content -->
        <!-- commodity is returned from the JSON fetch response -->
        ${commodity.userDescription}<span>${commodity.symbol}</span>
      </th>
    </tr>
    <tr>
      <!-- Static HTML table content -->
      <th scope="col">Month</th>
      <th scope="col">Last</th>
      <th scope="col">Change</th>
      <th scope="col">High</th>
      <th scope="col">Low</th>
      <th scope="col">Settle Date</th>
      <th scope="col">Settle Price</th>
      <th scope="col">More</th>
    </tr>
    <tr>
      <!-- Dynamic HTML table content -->
      <td>August 2022</td>
      <td>1265'2</td>
      <td>-2'4</td>
      <td>1275'2</td>
      <td>1261'4</td>
      <td>October 27, 2021</td>
      <td>1265'2</td>
      <td>Icon</td>
    </tr>
    <tr>
      <!-- Dynamic HTML table content -->
      <td>August 2022</td>
      <td>1265'2</td>
      <td>-2'4</td>
      <td>1275'2</td>
      <td>1261'4</td>
      <td>October 27, 2021</td>
      <td>1265'2</td>
      <td>Icon</td>
    </tr>
  </tbody>
</table>
Mike Hermary
  • 346
  • 7
  • 22

2 Answers2

0

I believe the issue here is that in dataRow you are displaying whole data, which is why the column names are repeated.

You can group commodities with same name.

For grouping the data you can refer https://stackoverflow.com/a/54203304/17090620.

And then while displaying the table it would be like,

dataColumn = `
<thead>
        <tr>
          <th colspan="9">${name}</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>Month</th>
          <th>Symbol</th>
          <th>Last</th>
          <th>Change</th>
          <th>High</th>
          <th>Low</th>
          <th>Settle Date</th>
          <th>Settle Price</th>
          <th>More</th>
        </tr>
`
dataRow = groupedCommodities[name].map((item) => 
<tr>
<td>${item.month}</td>
<td>${item.symbol}</td>
...
</tr>
)
futuresTable.insertAdjacentHTML("beforeend", dataColumn);
futuresTable.insertAdjacentHTML("beforeend", dataRow);
futuresTable.insertAdjacentHTML("beforeend", `</tbody>`);

Something like this should work.

  • 1
    Be careful about simply concatenating data into HTML. It can lead to invalid HTML or even XSS vulnerabilities. The data must be escaped properly. Best to use a proper template engine for this. – Brad Dec 24 '21 at 06:55
-1

I think your problem reference to call stack. Try to finished the fetch data from API then use displayData to display table. You can find out await or Promise in JavaScript. Thanks

Em Ha Tuan
  • 65
  • 9
  • 1
    Sorry, but this answer does not address my issue. The fetch request works fine. The issue lies with outputting the returned data using the structure I detailed above. – Mike Hermary Dec 20 '21 at 19:52