How to make HTML table expand on click?

2020-02-01 01:28发布

问题:

I am rendering HTML table with the help of JavaScript. I have made the table successfully, but now I have one requirement to show some new data in a row like on click expand row

Table functionality:

  • I am populating my table Some brand wise each brand has some items inside them, which I want to show when the brand is clicked
  • I almost created the table, but not able to create the expandable row
  • My one of column is populating wrong data also

In my code I have commented all the lines what I am doing at which line

Issues I am facing

  • I have already commented the line where I am calculating netamount to populate inside tbody as GRN entery brand wise but that's causing the issue

I have created two code snippets one as full static HTML like what I want, and a second to show what I have done.

The help I have found on Google

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">

<table class="table table-responsive table-hover table-bordered">
  <thead>
    <tr>
      <th> Brand Name</th>
      <th colspan="2">Total</th>
      <th colspan="2">Jayanagar</th>
      <th colspan="2">Malleshwaram</th>
      <th colspan="2">Kolar</th>
    </tr>
    <tr>
      <th></th>
      <th>Grn Entery</th>
      <th>Sales</th>
      <th>Grn Entery</th>
      <th>Sales</th>
      <th>Grn Entery</th>
      <th>Sales</th>
      <th>Grn Entery</th>
      <th>Sales</th>
    </tr>
    <tr>
      <th>Total</th>
      <th>1,97,445</th>
      <th>6,83,880</th>
      <th>1,97,445</th>
      <th>4,76,426</th>
      <th>0</th>
      <th>1,15,313</th>
      <th>0</th>
      <th>92,141</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><span class="clickable" data-toggle="collapse" id="row1" data-target=".row1"><i class="fas fa-plus" id="test"></i>&nbsp</span>Bakery FG</td>
      <td>1,610</td>
      <td>0.82%</td>
      <td>1,610 </td>
      <td>0.82%</td>
      <!--  this is comming as (1610/197445)*100 -->
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row1">
      <td>Khara Boondhi-L</td>
      <td>980</td>
      <td>0.50%</td>
      <td>980</td>
      <td>0.50%</td>
      <!--  this is comming as (980/197445)*100 -->
      <td>0</td>
      <td>0.00%</td>
      <!-- lly for other outlets it will be calculated  -->
      <td>0</td>
      <td>0.00%</td>
    </tr>
    <tr class="collapse row1">
      <td>Samosa-L</td>
      <td>130</td>
      <td>0.7%</td>
      <td>130</td>
      <td>0.7%</td>
      <!--  this is comming as (130/197445)*100 -->
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>
    </tr>
    <tr class="collapse row1">
      <td>Corn Flakes Masala-L</td>
      <td>500</td>
      <td>0.25%</td>
      <td>500</td>
      <td>0.25%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>
    </tr>
    <tr>
      <td><span class="clickable" data-toggle="collapse" data-target=".row2"><i class="fas fa-plus" id="test"></i>&nbsp</span>Pastry & Cake FG</td>
      <td>49,230</td>
      <td>25.00%</td>
      <td>49,230</td>
      <td>25.00%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row2">
      <td>Plum Cake 250gm</td>
      <td>110</td>
      <td>0.05%</td>
      <td>110</td>
      <td>0.05%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row2">
      <td>Butterscotch Cake</td>
      <td>720</td>
      <td>0.36%</td>
      <td>720</td>
      <td>0.36%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row2">
      <td>Chocolate chips cake</td>
      <td>40000</td>
      <td>20.25%</td>
      <td>40000</td>
      <td>20.25%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row2">
      <td>Mango Delight Cake</td>
      <td>14000</td>
      <td>7.09%</td>
      <td>14000</td>
      <td>7.09%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>


    </tr>
    <tr class="collapse row2">
      <td>Almond Honey Chocolate Cake</td>
      <td>500</td>
      <td>0.25%
        <td>500</td>
        <td>0.25%
          <td>0</td>
          <td>0.00%</td>
          <td>0</td>
          <td>0.00%</td>


    </tr>
    <tr class="collapse row2">
      <td>Peach Cake</td>
      <td>5500</td>
      <td>2.78%</td>
      <td>5500</td>
      <td>2.78%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row2">
      <td>Black Forest Cake</td>
      <td>1000</td>
      <td>0.50%</td>
      <td>1000</td>
      <td>0.50%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr>
      <td><span class="clickable" data-toggle="collapse" data-target=".row3"><i class="fas fa-plus" id="test"></i>&nbsp</span>Ice Cream FG</td>
      <td>108441</td>
      <td>54.92%</td>
      <td>108441</td>
      <td>54.92%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Chocolate Crazy Boom</td>
      <td>2360</td>
      <td>1.19%</td>
      <td>2360</td>
      <td>1.19%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>


    </tr>
    <tr class="collapse row3">
      <td>Kesar Badam Falooda</td>
      <td>4430</td>
      <td>2.24%</td>
      <td>4430</td>
      <td>2.24%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>


    </tr>
    <tr class="collapse row3">
      <td>Strawberry Ice-cream</td>
      <td>1231</td>
      <td>0.62%</td>
      <td>1231</td>
      <td>0.62%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>


    </tr>
    <tr class="collapse row3">
      <td>TOP- Chocochips</td>
      <td>2200</td>
      <td>1.11%</td>
      <td>2200</td>
      <td>1.11%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Cheese Cake Ice-Cream</td>
      <td>500</td>
      <td>0.25%</td>
      <td>500</td>
      <td>0.25%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Sundae Large</td>
      <td>2350</td>
      <td>1.20%</td>
      <td>2350</td>
      <td>1.20%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Mango Ice-cream</td>
      <td>8000</td>
      <td>40.5%</td>
      <td>8000</td>
      <td>40.5%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Ice Blue Sundae</td>
      <td>2340</td>
      <td>1.19%</td>
      <td>2340</td>
      <td>1.19%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Creamy Litchi Boom</td>
      <td>2200</td>
      <td>1.11%</td>
      <td>2200</td>
      <td>1.11%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Cookies Ice-cream</td>
      <td>7000</td>
      <td>3.54%</td>
      <td>7000</td>
      <td>3.54%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>TOP- Wafer</td>
      <td>88000</td>
      <td>44.56%</td>
      <td>88000</td>
      <td>44.56%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Litchi cherry Sundae</td>
      <td>2440</td>
      <td>1.23%</td>
      <td>2440</td>
      <td>1.23%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Peach Malaba</td>
      <td>2230</td>
      <td>1.12%</td>
      <td>2230</td>
      <td>1.12%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row3">
      <td>Cherry Mania Ice-Cream</td>
      <td>2700</td>
      <td>1.36%</td>
      <td>2700</td>
      <td>1.36%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr>
      <td><span class="clickable" data-toggle="collapse" data-target=".row4"><i class="fas fa-plus" id="test"></i>&nbsp</span>North Indian FG</td>
      <td>324</td>
      <td>0.17%</td>
      <td>324</td>
      <td>0.17%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>

    </tr>
    <tr class="collapse row4">
      <td>Fruit Mixture</td>
      <td>324</td>
      <td>0.17%</td>
      <td>324</td>
      <td>0.17%</td>
      <td>0</td>
      <td>0.00%</td>
      <td>0</td>
      <td>0.00%</td>
    </tr>



  </tbody>
</table>

I want to create something like the above snippet, but its expanding on clicking of row. I want to do it when the user clicks on plus icon, which I figured out how to do.

My dynamic code with JSON data

function format(number, decimals = 2, locale = 'en-in') {
  const fixed = parseInt(number).toFixed(decimals);
  const [int, dec] = fixed.split('.')
  const intFormatted = (+int).toLocaleString(locale)
  return intFormatted + (dec ? '.' + dec : '');
}
var data = [{
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Khara Boondhi-L",
    "transactionType": "TransferIn",
    "netamount": 980
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Samosa-L",
    "transactionType": "TransferIn",
    "netamount": 130
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Corn Flakes Masala-L",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Plum Cake 250gm",
    "transactionType": "TransferIn",
    "netamount": 110
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Butterscotch Cake",
    "transactionType": "TransferIn",
    "netamount": 720
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Chocolate chips cake",
    "transactionType": "TransferIn",
    "netamount": 40000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Mango Delight Cake",
    "transactionType": "TransferIn",
    "netamount": 14000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Almond Honey Chocolate Cake",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Peach Cake",
    "transactionType": "TransferIn",
    "netamount": 5500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Black Forest Cake",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Crazy Boom",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Hot Chocolate Fudge",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Sugar Free Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Kesar Badam Falooda",
    "transactionType": "TransferIn",
    "netamount": 4430
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Strawberry Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 1231
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Chocochips",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cheese Cake Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Sundae Large",
    "transactionType": "TransferIn",
    "netamount": 2350
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Mango Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 8000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Shooting Star",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Ice Blue Sundae",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Creamy Litchi Boom",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cookies Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 7000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Wafer",
    "transactionType": "TransferIn",
    "netamount": 88000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Litchi cherry Sundae",
    "transactionType": "TransferIn",
    "netamount": 2440
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Peach Malaba",
    "transactionType": "TransferIn",
    "netamount": 2230
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cherry Mania Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 2700
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "North Indian FG",
    "itemname": "Fruit Mixture",
    "transactionType": "TransferIn",
    "netamount": 324
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 476426
  },
  {
    "outlet": "KOLAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 115313
  },
  {
    "outlet": "MALLESHWARAM",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 92141
  }
]
let formatData = function(data) {
  let brandnames = [];
  let itemnames = [];
  let outlets = [];
  let maxUniqueForOutlets = {};
  data.forEach(element => {

    if (!maxUniqueForOutlets[element["brandname"]]) {
// i just want to filter this brand and items whichhave NA
      maxUniqueForOutlets[element["brandname"]] = [];
      console.log(maxUniqueForOutlets[element["brandname"]]) //key value pair of brandname and itemname
    }
    if (maxUniqueForOutlets[element["brandname"]].indexOf(element["itemname"]) == -1) {
      maxUniqueForOutlets[element["brandname"]].push(element["itemname"]);
    }

    if (brandnames.indexOf(element.brandname) == -1 && (element.brandname) !== "NA") { //taking brandname which do not have bradname===NA
      brandnames.push(element.brandname);
    }
    if (itemnames.indexOf(element.itemname) == -1 && (element.itemname) !== "NA") { //taking itemname which do not have bradname===NA
      itemnames.push(element.itemname);

    }
    if (outlets.indexOf(element.outlet) == -1) {
      outlets.push(element.outlet);
    }
  });


  return {
    data: data,
    brandnames: brandnames,
    itemnames: itemnames,
    outlets: outlets,
    maxUniqueForOutlets: maxUniqueForOutlets
  };
};
var totalSalesPercentage = '';
var olWiseSalesPercentage = '';
let renderTable = function(data) {
  let brandnames = data.brandnames;
  let itemnames = data.itemnames;
  let outlets = data.outlets;
  let maxUniqueForOutlets = data.maxUniqueForOutlets;
  data = data.data;
  let tbl = document.getElementById("ConsumptionTable");
  let table = document.createElement("table");
  let thead = document.createElement("thead");
  let headerRow = document.createElement("tr");
  let th = document.createElement("th");

  th = document.createElement("th");
  th.innerHTML = "Brand Name";
  th.classList.add("text-center");
  headerRow.appendChild(th);

  let grandTotal = 0;
  let grandNetAmount = 0;
  let outletWiseTotal = {};
  let outletWiseNetamount = {};
  th = document.createElement("th");
  th.colSpan = 2;
  th.innerHTML = "Total";
  th.classList.add("text-center");
  headerRow.appendChild(th);

  outlets.forEach(element => {

    th = document.createElement("th");
    th.colSpan = 2;
    th.innerHTML = element; // populating outlet 
    th.classList.add("text-center");
    headerRow.appendChild(th);
    outletWiseTotal[element] = 0;
    data.forEach(el => {
      if (el.outlet == element && el.brandname !== "NA") { //taking brandname which do not have bradname===NA
        outletWiseTotal[element] += parseInt(el.netamount); //here i am calculating the outletWiseTotal where transcationType==TransferIn

      }
      if (el.outlet == element && el.brandname == "NA" && el.transactionType == "Sales") { //taking brandname which do not have bradname===NA
        outletWiseNetamount[element] = parseInt(el.netamount) || 0


      }

    });
    grandTotal += outletWiseTotal[element]; //then calculating grand total to populate it into  Total column at grn entery

    grandNetAmount += outletWiseNetamount[element] || 0

  });

  thead.appendChild(headerRow);
  headerRow = document.createElement("tr");
  th = document.createElement("th");
  th.innerHTML = "";
  headerRow.appendChild(th);

  for (let i = 0; i < outlets.length + 1; i++) {
    th = document.createElement("th");
    th.innerHTML = "Sales";
    th.classList.add("text-center");
    headerRow.appendChild(th);

    th = document.createElement("th");
    th.innerHTML = "Grn Entery";
    th.classList.add("text-center");
    headerRow.appendChild(th);
  }

  headerRow.insertBefore(th, headerRow.children[1]);
  thead.appendChild(headerRow);
  table.appendChild(thead);

  headerRow = document.createElement("tr");
  let td = document.createElement("th");
  td.innerHTML = "Total";
  td.classList.add("text-center");
  headerRow.appendChild(td);
  let el1 = 0;
  outlets.forEach(element => {

    td = document.createElement("th");
    td.innerHTML = outletWiseTotal[element].toLocaleString('en-IN');
    td.classList.add("text-right");
    headerRow.appendChild(td);
    if (element.outlet == element) {
      el1 = element.netAmount;
    }
    td = document.createElement("th");
    td.innerHTML = outletWiseNetamount[element].toLocaleString('en-IN') || 0;
    td.classList.add("text-right");
    headerRow.appendChild(td);

  });
  td = document.createElement("th");
  td.innerHTML = grandNetAmount.toLocaleString('en-IN');
  td.classList.add("text-right");
  headerRow.insertBefore(td, headerRow.children[1]);

  td = document.createElement("th");
  td.innerHTML = grandTotal.toLocaleString('en-IN');
  td.classList.add("text-right");
  headerRow.insertBefore(td, headerRow.children[1]);
  thead.appendChild(headerRow);
  table.appendChild(thead);

  let tbody = document.createElement("tbody");

  Object.keys(maxUniqueForOutlets).forEach(function(element) { // rendering brand name
    let row = document.createElement("tr");
    row.classList.add('header');
    td = document.createElement("td");
    td.innerHTML = '<span><i class="fas fa-plus" id="test"></i>&nbsp</span>' + element; //creating plus font icon to make click happen

    row.appendChild(td);


    let total = 0;
    let totalBCount = 0;
    outlets.forEach(outlet => {
      let el = 0;
      let bc = 0;
      data.forEach(d => {
        if (d.brandname == element && d.outlet == outlet) {
          total += parseInt(d.netamount);
          el = d.netamount; //calculating outlet wise net amount

        }

      });


      olWiseSalesPercentage = (el / outletWiseTotal[outlet]) * 100 || 0
      td = document.createElement("td");
      td.innerHTML = el.toLocaleString('en-IN'); // by this one i am populating outlet wise values for bramd but it is displaying wrong values

      td.classList.add("text-right");
      row.appendChild(td);
      td = document.createElement("td");
      td.innerHTML = olWiseSalesPercentage.toFixed(2) + "%";

      td.classList.add("text-right");
      row.appendChild(td);
    });

    totalSalesPercentage = (total / grandTotal) * 100 //here doing some calculations
    const totalSalesPercentageFix = totalSalesPercentage.toFixed(2) + "%"
    td = document.createElement("td");
    td.innerHTML = totalSalesPercentageFix;
    td.classList.add("text-right");
    row.insertBefore(td, row.children[1]);

    td = document.createElement("td");
    td.innerHTML = total.toLocaleString('en-IN');
    td.classList.add("text-right");
    row.insertBefore(td, row.children[1]);





    tbody.appendChild(row);


    maxUniqueForOutlets[element].forEach(function(k) { //this one is populating itemwise values but it starts with Total column Total column will populate Total 
      let rowChildren = document.createElement("tr");
      const filteredData = data.filter(a => a.itemname === k);
      if (filteredData.length > 0) {
        var tdNew = document.createElement("td");
        tdNew.innerHTML = filteredData[0].netamount;
        tdNew.classList.add("text-right");
        var tdName = document.createElement("td");
        tdName.innerHTML = filteredData[0].itemname;
        tdName.classList.add("text-left");
        rowChildren.appendChild(tdName);
        rowChildren.appendChild(tdNew);
        outlets.forEach(outlet => {
          const emptyCell = document.createElement('td'); //this i am creating staticly how can i create this statically as here i have 3 outlets so i am creating 
          emptyCell.innerHTML = "12";
          emptyCell.classList.add("text-right");
          rowChildren.appendChild(emptyCell);

          const emptyCell1 = document.createElement('td');
          emptyCell1.innerHTML = "13";
          emptyCell1.classList.add("text-right");
          rowChildren.appendChild(emptyCell1);


          tbody.appendChild(rowChildren);
        });
      }
    })
  });

  table.appendChild(tbody);
  tbl.innerHTML = "";
  tbl.appendChild(table);
  table.classList.add("table");
  table.classList.add("table-striped");
  table.classList.add("table-bordered");
  table.classList.add("table-hover");

}
let formatedData = formatData(data);
renderTable(formatedData);


var ua = navigator.userAgent,
  event = (ua.match(/iPad/i)) ? "touchstart" : "click";
$('.table .header .fa-plus').on(event, function() {
  $(this).closest('.header').toggleClass("active", "").nextUntil('.header').css('display', function(i, v) {
    return this.style.display === 'table-row' ? 'none' : 'table-row';
  });
});
#test {
  color: green;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<div align="center" class="table table-responsive">
  <table id="ConsumptionTable"></table>
</div>

I have tried the other approach, which was when the user clicks on any brand I was making an Ajax call and running the query on the basis of that brand name and getting data, but still not able to get the expand functionality.

Now I realised that this is the best approach to get the data at once, then make table with that; I am just struggling to get it right

Dynamic Code Working process

  • Currently I have table with Brand Name,Grn Entery,Sales Sales body data which is in percentage I am calculating it by dividing grn by Total grn of that column and dividing it by 100
  • So when user clicks on any brand names's icon that is plus in my case I want to expand rows with all itemnames of that brand and whole structure of table will be same as it is for brandname wise, grn calculation wil all be according to item name, currently it is as per brand name

Edit/update

I am having some issues:

  • First of all using this code I am geting brand names and item names but it is taking NA also, I have tried to filter it out but haven't succeeded. Please check my snippet, I have commented all lines there.

  • when there is transactiontype:sales and itemname and brandname= NA then I am populating those values in header as sales value they don't have any relation with calculating percentage

  • when I am populating the item inside brand there I have to do it dynamically I have tried but didn't get that

回答1:

Do it this way, follow DRY and modular structure to keep it more readable and maintainable.

class CellEntry {
  constructor() {
    this.sum = 0;
    this.percentage = 0;
  }
}

class OutletBasedRowEntry {
  constructor() {
    this.cells = {
      Total: new CellEntry()
    };
    this.childRows = {};
  }
  add(entry) {
    this.cells.Total.sum += entry.netamount;
    this.getOrCreateCellById(entry.outlet).sum += entry.netamount;
  }
  getOrCreateChildRowById(id) {
    if (!this.childRows[id]) this.childRows[id] = new OutletBasedRowEntry();
    return this.childRows[id];
  }
  getOrCreateCellById(id) {
    if (!this.cells[id]) this.cells[id] = new CellEntry();
    return this.cells[id];
  }
}

function tabulizeData(data) {
  let TotalRowEntry = new OutletBasedRowEntry();
  data.forEach(entry => {
    TotalRowEntry.add(entry);
    TotalRowEntry.getOrCreateChildRowById(entry.brandname).add(entry);
    TotalRowEntry.getOrCreateChildRowById(entry.brandname).getOrCreateChildRowById(entry.itemname).add(entry);
  });
  renderTable(TotalRowEntry);
}

function renderTable(TotalRowEntry) {
  let $table = $('#ConsumptionTable');
  let $thead = $('<thead><tr><th>Brand Name</th></tr><tr><th></th></tr><tr><th>Total</th></tr><thead>'),
    $tbody = $('<tbody>');
  let $headingRows = $thead.find('tr');

  function addCellEntriesToRow(rowEntry, $row) {
    for (let cellName in TotalRowEntry.cells) {
      let cellEntry = rowEntry.getOrCreateCellById(cellName);
      $('<td>').html(cellEntry.sum).appendTo($row);
      $('<td>').html(cellEntry.percentage).appendTo($row);
    }
  }

  $.each(TotalRowEntry.cells, function(cellName, cellEntry) {
    $('<th colspan=2>').html(cellName).appendTo($headingRows.eq(0));
    $('<th>Grn Entery</th>').appendTo($headingRows.eq(1));
    $('<th>Sales</th>').appendTo($headingRows.eq(1));
    $('<th>').html(cellEntry.sum).appendTo($headingRows.eq(2));
    $('<th>').html(cellEntry.percentage).appendTo($headingRows.eq(2));
  });

  $.each(TotalRowEntry.childRows, function(brandName, rowEntry) {
    let $row = $('<tr>').appendTo($tbody);
    let rowId = 'row' + $row.index();
    let firstCell = $('<td><i class="fas fa-plus add-btn" data-toggle="collapse" data-target=".' + rowId + '"></i>' + brandName + '</td>').appendTo($row);
    addCellEntriesToRow(rowEntry, $row);
    $.each(rowEntry.childRows, function(itemName, rowEntry) {
      $row = $('<tr>').addClass('collapse ' + rowId).appendTo($tbody);
      $('<td>').html(itemName).appendTo($row);
      addCellEntriesToRow(rowEntry, $row);
    });
  });

  $thead.appendTo($table);
  $tbody.appendTo($table);
}

tabulizeData([{
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Khara Boondhi-L",
    "transactionType": "TransferIn",
    "netamount": 980
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Samosa-L",
    "transactionType": "TransferIn",
    "netamount": 130
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Corn Flakes Masala-L",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Plum Cake 250gm",
    "transactionType": "TransferIn",
    "netamount": 110
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Butterscotch Cake",
    "transactionType": "TransferIn",
    "netamount": 720
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Chocolate chips cake",
    "transactionType": "TransferIn",
    "netamount": 40000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Mango Delight Cake",
    "transactionType": "TransferIn",
    "netamount": 14000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Almond Honey Chocolate Cake",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Peach Cake",
    "transactionType": "TransferIn",
    "netamount": 5500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Black Forest Cake",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Crazy Boom",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Hot Chocolate Fudge",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Sugar Free Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Kesar Badam Falooda",
    "transactionType": "TransferIn",
    "netamount": 4430
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Strawberry Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 1231
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Chocochips",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cheese Cake Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Sundae Large",
    "transactionType": "TransferIn",
    "netamount": 2350
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Mango Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 8000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Shooting Star",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Ice Blue Sundae",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Creamy Litchi Boom",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cookies Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 7000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Wafer",
    "transactionType": "TransferIn",
    "netamount": 88000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Litchi cherry Sundae",
    "transactionType": "TransferIn",
    "netamount": 2440
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Peach Malaba",
    "transactionType": "TransferIn",
    "netamount": 2230
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cherry Mania Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 2700
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "North Indian FG",
    "itemname": "Fruit Mixture",
    "transactionType": "TransferIn",
    "netamount": 324
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 476426
  },
  {
    "outlet": "KOLAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 115313
  },
  {
    "outlet": "MALLESHWARAM",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 92141
  }
]);
.add-btn {
  color: green;
  cursor: pointer;
  margin-right: 6px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<div align="center" class="table table-responsive">
  <table id="ConsumptionTable" class="table table-responsive table-hover table-bordered"></table>
</div>



回答2:

I suggest you use DataTables.

DataTables offers a rich API for rendering row data, show/hiding columns, search/filter, paging, etc. It can be styled through jQuery UI or Bootstrap, or your own branding. In contrast to writing up your own table display logic, the DataTables libraries are free to use and extremely flexible.

See: https://datatables.net/examples/api/row_details.html



回答3:

Pass "the row was clicked" or "the row we want to add some rows after" to the expand function

td.addEventListener('click', function(){
    expand(row);
});

Then just expand new rows using:

function insertAfter(elm, newElm) {
    elm.parentNode.insertBefore(newElm, elm.nextSibling);
}

Sample code down below:

function format(number, decimals = 2, locale = 'en-in') {
  const fixed = parseInt(number).toFixed(decimals);
  const [int, dec] = fixed.split('.')
  const intFormatted = (+int).toLocaleString(locale)
  return intFormatted + (dec ? '.' + dec : '');
}
var data = [{
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Khara Boondhi-L",
    "transactionType": "TransferIn",
    "netamount": 980
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Samosa-L",
    "transactionType": "TransferIn",
    "netamount": 130
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Corn Flakes Masala-L",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Plum Cake 250gm",
    "transactionType": "TransferIn",
    "netamount": 110
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Butterscotch Cake",
    "transactionType": "TransferIn",
    "netamount": 720
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Chocolate chips cake",
    "transactionType": "TransferIn",
    "netamount": 40000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Mango Delight Cake",
    "transactionType": "TransferIn",
    "netamount": 14000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Almond Honey Chocolate Cake",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Peach Cake",
    "transactionType": "TransferIn",
    "netamount": 5500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Black Forest Cake",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Crazy Boom",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Hot Chocolate Fudge",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Sugar Free Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Kesar Badam Falooda",
    "transactionType": "TransferIn",
    "netamount": 4430
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Strawberry Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 1231
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Chocochips",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cheese Cake Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Sundae Large",
    "transactionType": "TransferIn",
    "netamount": 2350
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Mango Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 8000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Shooting Star",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Ice Blue Sundae",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Creamy Litchi Boom",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cookies Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 7000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Wafer",
    "transactionType": "TransferIn",
    "netamount": 88000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Litchi cherry Sundae",
    "transactionType": "TransferIn",
    "netamount": 2440
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Peach Malaba",
    "transactionType": "TransferIn",
    "netamount": 2230
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cherry Mania Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 2700
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "North Indian FG",
    "itemname": "Fruit Mixture",
    "transactionType": "TransferIn",
    "netamount": 324
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 476426
  },
  {
    "outlet": "KOLAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 115313
  },
  {
    "outlet": "MALLESHWARAM",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 92141
  }
]
let formatData = function(data) {
  let brandnames = [];
  let itemnames = [];
  let outlets = [];
  data.forEach(element => {
    if (brandnames.indexOf(element.brandname) == -1 && (element.brandname) !== "NA") { //taking brandname which do not have bradname===NA
      brandnames.push(element.brandname);
    }
    if (itemnames.indexOf(element.itemname) == -1 && (element.itemname) !== "NA") { //taking itemname which do not have bradname===NA
      itemnames.push(element.itemname);
    }
    if (outlets.indexOf(element.outlet) == -1) {
      outlets.push(element.outlet);
    }
  });
  return {
    data: data,
    brandnames: brandnames,
    itemnames: itemnames,
    outlets: outlets,
  };
};
var totalSalesPercentage = '';
var olWiseSalesPercentage = '';
let renderTable = function(data) {
  brandnames = data.brandnames;
  itemnames = data.itemnames;
  outlets = data.outlets;
  data = data.data;
  let tbl = document.getElementById("ConsumptionTable");
  let table = document.createElement("table");
  let thead = document.createElement("thead");
  let headerRow = document.createElement("tr");
  let th = document.createElement("th");

  th = document.createElement("th");
  th.innerHTML = "Brand Name";
  th.classList.add("text-center");
  headerRow.appendChild(th);

  let grandTotal = 0;
  let grandNetAmount = 0;
  let outletWiseTotal = {};
  let outletWiseNetamount = {};
  th = document.createElement("th");
  th.colSpan = 2;
  th.innerHTML = "Total";
  th.classList.add("text-center");
  headerRow.appendChild(th);

  outlets.forEach(element => {

    th = document.createElement("th");
    th.colSpan = 2;
    th.innerHTML = element; // populating outlet 
    th.classList.add("text-center");
    headerRow.appendChild(th);
    outletWiseTotal[element] = 0;
    data.forEach(el => {
      if (el.outlet == element && el.brandname !== "NA") { //taking brandname which do not have bradname===NA
        outletWiseTotal[element] += parseInt(el.netamount); //here i am calculating the outletWiseTotal where transcationType==TransferIn

      }
      if (el.outlet == element && el.brandname == "NA" && el.transactionType == "Sales") { //taking brandname which do not have bradname===NA
        outletWiseNetamount[element] = parseInt(el.netamount) || 0


      }

    });
    grandTotal += outletWiseTotal[element]; //then calculating grand total to populate it into  Total column at grn entery

    grandNetAmount += outletWiseNetamount[element] || 0

  });

  thead.appendChild(headerRow);
  headerRow = document.createElement("tr");
  th = document.createElement("th");
  th.innerHTML = "";
  headerRow.appendChild(th);

  for (i = 0; i < outlets.length + 1; i++) {
    th = document.createElement("th");
    th.innerHTML = "Sales";
    th.classList.add("text-center");
    headerRow.appendChild(th);

    th = document.createElement("th");
    th.innerHTML = "Grn Entery";
    th.classList.add("text-center");
    headerRow.appendChild(th);
  }

  headerRow.insertBefore(th, headerRow.children[1]);
  thead.appendChild(headerRow);
  table.appendChild(thead);

  headerRow = document.createElement("tr");
  td = document.createElement("th");
  td.innerHTML = "Total";
  td.classList.add("text-center");
  headerRow.appendChild(td);
  let el1 = 0;
  outlets.forEach(element => {

    td = document.createElement("th");
    td.innerHTML = outletWiseTotal[element].toLocaleString('en-IN');
    td.classList.add("text-right");
    headerRow.appendChild(td);
    if (element.outlet == element) {
      el1 = element.netAmount;
    }
    td = document.createElement("th");
    td.innerHTML = outletWiseNetamount[element].toLocaleString('en-IN') || 0;
    td.classList.add("text-right");
    headerRow.appendChild(td);

  });
  td = document.createElement("th");
  td.innerHTML = grandNetAmount.toLocaleString('en-IN');
  td.classList.add("text-right");
  headerRow.insertBefore(td, headerRow.children[1]);

  td = document.createElement("th");
  td.innerHTML = grandTotal.toLocaleString('en-IN');
  td.classList.add("text-right");
  headerRow.insertBefore(td, headerRow.children[1]);
  thead.appendChild(headerRow);
  table.appendChild(thead);

  let tbody = document.createElement("tbody");
  brandnames.forEach(element => {
    let row = document.createElement("tr");

    td = document.createElement("td");
    td.innerHTML = '<span><i class="fas fa-plus" id="test"></i>&nbsp</span>' + " " + element; //creating plus font icon to make click happen
    
    /*  
     * Pass the row was clicked to the expand function
     */
    td.addEventListener('click', function(){
      expand(row);
    });

    row.appendChild(td);
    let total = 0;
    let totalBCount = 0;
    outlets.forEach(outlet => {
      let el = 0;
      let bc = 0;
      data.forEach(d => {
        if (d.brandname == element && d.outlet == outlet) {
          total += parseInt(d.netamount);
          el = d.netamount;
          console.log(el) //this one is populating ful data here
        }
      });
      console.log(el) //but here it is not taking cumulative sum of netamount it is only taking one amount of each brand 
      olWiseSalesPercentage = (el / outletWiseTotal[outlet]) * 100 || 0 //here doing some calculations
      td = document.createElement("td");
      td.innerHTML = el.toLocaleString('en-IN');

      td.classList.add("text-right");
      row.appendChild(td);
      td = document.createElement("td");
      td.innerHTML = olWiseSalesPercentage.toFixed(2) + "%";

      td.classList.add("text-right");
      row.appendChild(td);
    });
    totalSalesPercentage = (total / grandTotal) * 100 //here doing some calculations
    const totalSalesPercentageFix = totalSalesPercentage.toFixed(2) + "%"
    td = document.createElement("td");
    td.innerHTML = totalSalesPercentageFix;
    td.classList.add("text-right");
    row.insertBefore(td, row.children[1]);

    td = document.createElement("td");
    td.innerHTML = total.toLocaleString('en-IN');
    td.classList.add("text-right");
    row.insertBefore(td, row.children[1]);
    tbody.appendChild(row);
  });
  table.appendChild(tbody);
  tbl.innerHTML = "";
  tbl.appendChild(table);
  table.classList.add("table");
  table.classList.add("table-striped");
  table.classList.add("table-bordered");
  table.classList.add("table-hover");

}
let formatedData = formatData(data);
renderTable(formatedData);

/*  
 * Insert newElm after elm
 */
function insertAfter(elm, newElm) {
  elm.parentNode.insertBefore(newElm, elm.nextSibling);
}

/*  
 * Add detail row after clicked row
 */
function expand(row) {
    let detailRow = document.createElement("tr");
    let td = document.createElement("td");
    td.colSpan = 9;
    td.innerHTML = "Detail row goes here";
    detailRow.appendChild(td);
    insertAfter(row, detailRow);
}
#test {
  color: green;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<div align="center" class="table table-responsive">
  <table id="ConsumptionTable"></table>
</div>



回答4:

To achieve expected result, use below option of creating new table inside clicked td

  1. On Click of plus icon, get the brand name
  2. Filter items from data using brandname
  3. Creating table with items for that brand
  4. Hiding items row on selecting other row using class-itemsRow
  5. On Clicking already selecting , remove style display: none , instead of re-creating table

function format(number, decimals = 2, locale = 'en-in') {
  const fixed = parseInt(number).toFixed(decimals);
  const [int, dec] = fixed.split('.')
  const intFormatted = (+int).toLocaleString(locale)
  return intFormatted + (dec ? '.' + dec : '');
}
var data = [{
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Khara Boondhi-L",
    "transactionType": "TransferIn",
    "netamount": 980
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Samosa-L",
    "transactionType": "TransferIn",
    "netamount": 130
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Bakery FG",
    "itemname": "Corn Flakes Masala-L",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Plum Cake 250gm",
    "transactionType": "TransferIn",
    "netamount": 110
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Butterscotch Cake",
    "transactionType": "TransferIn",
    "netamount": 720
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Chocolate chips cake",
    "transactionType": "TransferIn",
    "netamount": 40000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Mango Delight Cake",
    "transactionType": "TransferIn",
    "netamount": 14000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Almond Honey Chocolate Cake",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Peach Cake",
    "transactionType": "TransferIn",
    "netamount": 5500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Pastry & Cake FG",
    "itemname": "Black Forest Cake",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Crazy Boom",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Hot Chocolate Fudge",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Chocolate Sugar Free Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 1000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Kesar Badam Falooda",
    "transactionType": "TransferIn",
    "netamount": 4430
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Strawberry Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 1231
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Chocochips",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cheese Cake Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 500
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Sundae Large",
    "transactionType": "TransferIn",
    "netamount": 2350
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Mango Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 8000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Shooting Star",
    "transactionType": "TransferIn",
    "netamount": 2360
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Ice Blue Sundae",
    "transactionType": "TransferIn",
    "netamount": 2340
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Creamy Litchi Boom",
    "transactionType": "TransferIn",
    "netamount": 2200
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cookies Ice-cream",
    "transactionType": "TransferIn",
    "netamount": 7000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "TOP- Wafer",
    "transactionType": "TransferIn",
    "netamount": 88000
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Litchi cherry Sundae",
    "transactionType": "TransferIn",
    "netamount": 2440
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Peach Malaba",
    "transactionType": "TransferIn",
    "netamount": 2230
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "Ice Cream FG",
    "itemname": "Cherry Mania Ice-Cream",
    "transactionType": "TransferIn",
    "netamount": 2700
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "North Indian FG",
    "itemname": "Fruit Mixture",
    "transactionType": "TransferIn",
    "netamount": 324
  },
  {
    "outlet": "JAYANAGAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 476426
  },
  {
    "outlet": "KOLAR",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 115313
  },
  {
    "outlet": "MALLESHWARAM",
    "brandname": "NA",
    "itemname": "NA",
    "transactionType": "Sales",
    "netamount": 92141
  }
]
let formatData = function(data) {
  let brandnames = [];
  let itemnames = [];
  let outlets = [];
  data.forEach(element => {
    if (brandnames.indexOf(element.brandname) == -1 && (element.brandname) !== "NA") { //taking brandname which do not have bradname===NA
      brandnames.push(element.brandname);
    }
    if (itemnames.indexOf(element.itemname) == -1 && (element.itemname) !== "NA") { //taking itemname which do not have bradname===NA
      itemnames.push(element.itemname);
    }
    if (outlets.indexOf(element.outlet) == -1) {
      outlets.push(element.outlet);
    }
  });
  return {
    data: data,
    brandnames: brandnames,
    itemnames: itemnames,
    outlets: outlets,
  };
};
var totalSalesPercentage = '';
var olWiseSalesPercentage = '';
let renderTable = function(data) {
  brandnames = data.brandnames;
  itemnames = data.itemnames;
  outlets = data.outlets;
  data = data.data;
  let tbl = document.getElementById("ConsumptionTable");
  let table = document.createElement("table");
  let thead = document.createElement("thead");
  let headerRow = document.createElement("tr");
  let th = document.createElement("th");

  th = document.createElement("th");
  th.innerHTML = "Brand Name";
  th.classList.add("text-center");
  headerRow.appendChild(th);

  let grandTotal = 0;
  let grandNetAmount = 0;
  let outletWiseTotal = {};
  let outletWiseNetamount = {};
  th = document.createElement("th");
  th.colSpan = 2;
  th.innerHTML = "Total";
  th.classList.add("text-center");
  headerRow.appendChild(th);

  outlets.forEach(element => {

    th = document.createElement("th");
    th.colSpan = 2;
    th.innerHTML = element; // populating outlet 
    th.classList.add("text-center");
    headerRow.appendChild(th);
    outletWiseTotal[element] = 0;
    data.forEach(el => {
      if (el.outlet == element && el.brandname !== "NA") { //taking brandname which do not have bradname===NA
        outletWiseTotal[element] += parseInt(el.netamount); //here i am calculating the outletWiseTotal where transcationType==TransferIn

      }
      if (el.outlet == element && el.brandname == "NA" && el.transactionType == "Sales") { //taking brandname which do not have bradname===NA
        outletWiseNetamount[element] = parseInt(el.netamount) || 0


      }

    });
    console.log(outletWiseTotal)
    grandTotal += outletWiseTotal[element]; //then calculating grand total to populate it into  Total column at grn entery

    grandNetAmount += outletWiseNetamount[element] || 0

  });

  thead.appendChild(headerRow);
  headerRow = document.createElement("tr");
  th = document.createElement("th");
  th.innerHTML = "";
  headerRow.appendChild(th);

  for (i = 0; i < outlets.length + 1; i++) {
    th = document.createElement("th");
    th.innerHTML = "Sales";
    th.classList.add("text-center");
    headerRow.appendChild(th);

    th = document.createElement("th");
    th.innerHTML = "Grn Entery";
    th.classList.add("text-center");
    headerRow.appendChild(th);
  }

  headerRow.insertBefore(th, headerRow.children[1]);
  thead.appendChild(headerRow);
  table.appendChild(thead);

  headerRow = document.createElement("tr");
  td = document.createElement("th");
  td.innerHTML = "Total";
  td.classList.add("text-center");
  headerRow.appendChild(td);
  let el1 = 0;
  outlets.forEach(element => {

    td = document.createElement("th");
    td.innerHTML = outletWiseTotal[element].toLocaleString('en-IN');
    td.classLis