Organize/Group HTML Tables By Certain Attribute

Viewed 173

I'll keep this short and sweet. I have a table that prints everything I need it to just fine. What I am trying to do is group the data rows under Program 1 together so instead of Program 1 printing, inserting the data, then printing again followed by another set of data, I want it to look like the "Expected Results" table. There are going to be way more than 2 per program, just used that as an example. I have been stuck on this for a while and just cannot seem to figure it out. I also would like to be able to collapse and expand these rows that way not everything is showing

Actual Result: Printed Table

**Expected Result** 
    +------------+----------------------+-----------+------------+--------------+--------------+
    | Program    | To                   |  Date     |   Approved | Notes        | Deliverable  |
    +------------+----------------------+-----------+------------+--------------+--------------+
    | Program 1  | example@example.com  | 12/23/2018| Yes        | Example Notes| MSR          |
    |            | example@example.com  | 03/30/2020| Yes        | Example Notes| Meeting Mins |
    +------------+----------------------+-----------+------------+--------------+--------------+
    | Program 2  | example@example.com  | 12/23/2018| Yes        | Example Notes| MSR          |
    |            | example@example.com  | 12/03/2017| Yes        | Example Notes| Meeting Mins |
    +------------+----------------------+-----------+------------+--------------+--------------+
    | Program 3  | example@example.com  | 04/17/2020| Yes        | Example Notes| MSR          |
    |            | example@example.com  | 03/30/2020| No         | Example Notes| Meeting Mins |
    +------------+----------------------+-----------+------------+--------------+--------------+

Here is my code:

<input type="text" id="myInput" onkeyup="searchTable()" placeholder="Search by Program Name" title="Enter Program Name">

<script src="/Scripts/jquery-3.3.1.min.js"></script>
<script>

var webAppUrl = _spPageContextInfo.webAbsoluteUrl;

function loadData(source, url) {
  return fetch(url, { headers: { accept: "application/json; odata=verbose" } }) // make request
    .then((r) => {
      if (!r.ok) throw new Error("Failed: " + url);  // Check for errors
      return r.json();  // parse JSON
    })
    .then((data) => data.d.results) // unwrap to get results array
    .then((results) => {
      results.forEach((r) => (r.source = source)); // add source to each item
      return results;
    });
}
window.addEventListener("load", function () {
  Promise.all([
    loadData("XDeliverables", webAppUrl + "/_api/web/lists/getbytitle('XDeliverables')/items?$select=Program,To,Date,Approved,Notes,Deliverable"),
    loadData("YDeliverables", webAppUrl + "/_api/web/lists/getbytitle('YDeliverables')/items?$select=Program,To,Date,Approved,Notes,Deliverable"),
    loadData("ZDeliverables", webAppUrl + "/_api/web/lists/getbytitle('ZDeliverables')/items?$select=Program,To,Date,Approved,Notes,Deliverable"),
  ])
        .then(([r1, r2, r3]) => {
      const objItems = r1.concat(r2,r3);
      console.log(objItems);
      var tableContent =
        '<table id="deliverablesTable" style="width:100%" border="1 px"><thead><tr><td><strong>Program</strong></td>' +
        "<td><strong>To</strong></td>" +
        "<td><strong>Date Submitted</strong></td>" +
        "<td><strong>Approved</strong></td>" +
        "<td><strong>Notes</strong></td>" +
        "<td><strong>Deliverable</strong></td>" +
        "</tr></thead><tbody>";

      for (var i = 0; i < objItems.length; i++) {
                tableContent += "<tr>";
                tableContent += "<td>" + objItems[i].Program + "</td>";
                tableContent += "</tr>";
                tableContent += "<tr>";
                tableContent += "<td> </td>";
                tableContent += "<td>" + objItems[i].To + "</td>";
                tableContent += "<td>" + objItems[i].Date + "</td>";
                tableContent += "<td>" + objItems[i].Approved + "</td>";
                tableContent += "<td>" + objItems[i].Notes + "</td>";
                tableContent += "<td>" + objItems[i].Deliverable + "</td>";
                tableContent += "</tr>";
      }
      $("#deliverables").append(tableContent);
    })
    .catch((err) => {
      alert("Error: " + err);
      console.error(err);
    });
});

Here is the Object Array returned in objItems

{"Notes": "Example Notes", "Approved": "Yes", "Program": "Prorgam 1", "Date": "12/23/2018", "To": "example@example.com", "source": "XDeliverables", "Deliverable": "Monthly Status Report (MSR)"},
{"Notes": "Example Notes", "Approved": "Yes", "Program": "Program 1", "Date": "03/30/2020", "To": "example@example.com", "source": "XDeliverables", "Deliverable": "Meeting Minutes"},
{"Notes": "Example Notes", "Approved": "Yes", "Program": "Program 2", "Date": "12/23/2018", "To": "example@example.com", "source": "YDeliverables", "Deliverable": "Monthly Status Report (MSR)"},
{"Notes": "Example Notes", "Approved": "Yes", "Program": "Program 2", "Date": "12/3/2017", "To": "example@example.com", "source": "YDeliverables", "Deliverable": "Meeting Minutes"},
{"Notes": "Example Notes", "Approved": "No", "Program": "Program 3", "Date": "4/17/2020", "To": "example@example.com", "source": "ZDeliverables", "Deliverable": "Monthly Status Report (MSR)"},
{"Notes": "Example Notes", "Approved": "Yes", "Program": "Program 3", "Date": "12/23/2018", "To": "example@example.com", "source": "ZDeliverables", "Deliverable": "Meeting Minutes"},
1 Answers

If think you need to sort and group the array before looping over it. Here is an example of a way to replace the for loop.

<input type="text" id="myInput" onkeyup="searchTable()" placeholder="Search by Program Name" title="Enter Program Name">

<script src="/Scripts/jquery-3.3.1.min.js"></script>
<script>

var webAppUrl = _spPageContextInfo.webAbsoluteUrl;

function loadData(source, url) {
  return fetch(url, { headers: { accept: "application/json; odata=verbose" } }) // make request
    .then((r) => {
      if (!r.ok) throw new Error("Failed: " + url);  // Check for errors
      return r.json();  // parse JSON
    })
    .then((data) => data.d.results) // unwrap to get results array
    .then((results) => {
      results.forEach((r) => (r.source = source)); // add source to each item
      return results;
    });
}
window.addEventListener("load", function () {
  Promise.all([
    loadData("XDeliverables", webAppUrl + "/_api/web/lists/getbytitle('XDeliverables')/items?$select=Program,To,Date,Approved,Notes,Deliverable"),
    loadData("YDeliverables", webAppUrl + "/_api/web/lists/getbytitle('YDeliverables')/items?$select=Program,To,Date,Approved,Notes,Deliverable"),
    loadData("ZDeliverables", webAppUrl + "/_api/web/lists/getbytitle('ZDeliverables')/items?$select=Program,To,Date,Approved,Notes,Deliverable"),
  ])
        .then(([r1, r2, r3]) => {
      const objItems = r1.concat(r2,r3);
      console.log(objItems);
      var tableContent =
        '<table id="deliverablesTable" style="width:100%" border="1 px"><thead><tr><td><strong>Program</strong></td>' +
        "<td><strong>To</strong></td>" +
        "<td><strong>Date Submitted</strong></td>" +
        "<td><strong>Approved</strong></td>" +
        "<td><strong>Notes</strong></td>" +
        "<td><strong>Deliverable</strong></td>" +
        "</tr></thead><tbody>";

      var sortedObj = {}
objItems.forEach(item => {
  var program = item.Program;
  delete(item.Program); //remove this line to keep the program in the item data
  if (!sortedObj[program]) {
    sortedObj[program] = [];
  }
  sortedObj[program].push(item);
});

//sort by deliverable
Object.keys(sortedObj).forEach(key => {
  sortedObj[key]
    .sort((a, b) => {
      if (a.Deliverable === b.Deliverable) {
        return 0;
      }
      return a.Deliverable > b.Deliverable ? 1 : -1;
    })
});

Object.keys(sortedObj).forEach((key, index) => {
  tableContent += "<tr id='parent-" + index + "' class='parent'>";
  tableContent += "<td>" + key + "</td>";
  tableContent += "</tr>";
  sortedObj[key].forEach(obj => {
    tableContent += "<tr class='child child-" + index + "'>";
    tableContent += "<td> </td>";
    tableContent += "<td>" + obj.To + "</td>";
    tableContent += "<td>" + obj.Date + "</td>";
    tableContent += "<td>" + obj.Approved + "</td>";
    tableContent += "<td>" + obj.Notes + "</td>";
    tableContent += "<td>" + obj.Deliverable + "</td>";
    tableContent += "</tr>";
  });
});
      $("#deliverables").append(tableContent);
    })
    .catch((err) => {
      alert("Error: " + err);
      console.error(err);
    });
});**strong text**
Related