【问题标题】:How to make HTML table expand on click?如何使 HTML 表格在点击时展开?
【发布时间】:2019-04-30 10:54:02
【问题描述】:

我在 JavaScript 的帮助下呈现 HTML 表格。我已经成功制作了表格,但现在我有一个要求是在一行中显示一些新数据,比如点击展开行

表格功能:

  • 我正在填充我的表一些品牌明智的每个品牌都有一些项目,我想在点击品牌时显示这些项目
  • 我几乎创建了表格,但无法创建可扩展行
  • 我的一列也填充了错误的数据

在我的代码中,我已经注释了我在哪一行所做的所有行

我面临的问题

  • 我已经评论了我计算 netamount 以填充 tbodyGRN entery 品牌明智的行,但这会导致问题

我创建了两个代码 sn-ps,一个是我想要的完全静态 HTML,另一个是显示我所做的。

我在 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>

我想创建类似于上面的 sn-p 的东西,但它会在单击行时扩展。当用户点击plus 图标时,我想这样做,我figured out how to do

我的 JSON 数据动态代码

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>

我尝试了另一种方法,即当用户单击任何品牌时,我正在进行 Ajax 调用并根据该品牌名称运行查询并获取数据,但仍然无法获得扩展功能。

现在我意识到这是一次获取数据然后用它制作表格的最佳方法;我只是在努力把它做好

动态代码工作流程

  • 目前我的表格包含Brand Name,Grn Entery,Sales 以百分比表示的销售主体数据,我通过将grn 除以该列的总grn 再除以100 来计算它
  • 因此,当用户单击任何品牌名称的图标(在我的情况下为 plus)时,我想用该品牌的所有项目名称扩展行,并且表的整个结构将与 brandname 相同,grn 计算都将根据商品名称,目前是根据品牌名称

编辑/更新

我遇到了一些问题:

  • 首先使用此代码我得到品牌名称和项目名称,但它也采用 NA,我试图将其过滤掉但没有成功。请检查我的 sn-p,我已经评论了那里的所有行。

  • 当存在 transactiontype:sales 和 itemname 和 brandname=NA 时,我将这些值填充到标题中作为销售值,它们与计算百分比没有任何关系

  • 当我在那里填充品牌内的项目时,我必须动态地进行我尝试过但没有得到它

【问题讨论】:

  • @RameshRajendran 谢谢,现在如果你能帮我一些代码,那会很有帮助
  • @NabeelShaikh 嘿,很好,我也创建了一个类似的 sn-p,但正如你所见,我正在使用 java-script 渲染我的表格,它是完全动态的,所以我被卡住了那里
  • 看来 jquery 在这里没有做任何事情......

标签: javascript jquery html html-table bootstrap-4


【解决方案1】:

我建议你使用 DataTables。

DataTables 提供了丰富的 API 用于呈现行数据、显示/隐藏列、搜索/过滤、分页等。它可以通过 jQuery UI 或 Bootstrap 或您自己的品牌来设置样式。与编写自己的表格显示逻辑相比,DataTables 库可以免费使用并且非常灵活。

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

【讨论】:

  • 我也试过了,但是看看加点击它以其他格式填充,我想扩展我的表格,因为它已经存在,我已经对我的帖子进行了编辑,请检查
  • 展开模板是一个纯html div/span..当项目展开时你可以有任何布局..使用数据表。让生活变得轻松......
  • 我已经用 java 脚本代码上传了我的 JSON,你能做到吗,因为我已经尝试了很多
  • 检查我的 codepen ---> codepen.io/nbaua/pen/WBNQVE 也分享为答案,如果有用,请将其标记为答案。
【解决方案2】:

这样做,遵循 DRY 和模块化结构,使其更具可读性和可维护性。

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>

【讨论】:

【解决方案3】:

将“该行被点击”或“我们要在其后添加一些行的行”传递给展开函数

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

然后只需使用以下命令扩展新行:

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

下面的示例代码:

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】:

    要达到预期的效果,请使用以下在点击的 td 内创建新表的选项

    1. 点击加号图标,获取品牌名称
    2. 使用品牌名称从数据中过滤项目
    3. 创建包含该品牌商品的表格
    4. 在使用 class-itemsRow 选择其他行时隐藏项目行
    5. 在单击已经选择时,删除样​​式显示:无,而不是重新创建表格

    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.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 onclick="expand(this)"><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;
              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);
    
    function expand(e) {
      let itemsRow = document.querySelectorAll('.itemsRow');
      if(itemsRow){
        itemsRow.forEach(v => v.style.display = 'none')
      }
        let list = e.parentNode.children;
        for (v of list){
          if(v.nodeName === 'TABLE'){
          v.style.display = '';
          return
        }
        }
     
    
      let brand = e.parentNode.innerHTML.substr(e.parentNode.innerHTML.lastIndexOf('>')+1).trim()
      let table = document.createElement("table");
      table.classList.add("itemsRow");
      let tbody = document.createElement("tbody");
    
      let brandNames = data.filter(v => v.brandname === brand)
      
      brandNames.forEach(element => {
        let row = document.createElement("tr");
        for (let property in element) {
              td = document.createElement("td"); 
              td.classList.add("items");
              td.innerHTML = element[property];
             row.appendChild(td)
      }
    
        tbody.appendChild(row)
      });
      table.appendChild(tbody);
      e.parentNode.appendChild(table);
    }
    #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>

    codepen - https://codepen.io/nagasai/pen/pBMgYv

    【讨论】:

    • 嘿,这不是我想要实现的,请检查我的编辑我已经使用一些静态 HTML 进行了更新,这些 HTML 具有与我的 JSON 中的匹配数据
    【解决方案5】:

    几乎是一个纯 JavaScript 解决方案示例,将标题的部分分解为函数,详细信息行的函数,它在其中查找标题以将金额放在下面 - 我添加了一个项目来证明这一点。

    如果您运行此程序,您可以展开顶部注释以查看我所做的事情的详细注释。 (点击蓝色大按钮)

    /*jshint esversion: 6 */
    
    var rawdata = [{
        "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": "MALLESHWARAM",
        "brandname": "My Pie",
        "itemname": "Cherry Pie",
        "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
      }
    ];
    
    // basic functions, work even in old browsers like ie6
    var myApp = myApp || {};
    myApp.funcs = {
      indexOf: function(myArray, searchTerm, property) {
        for (var i = 0; i < myArray.length; i++) {
          if (myArray[i][property] === searchTerm) return i;
        }
        return -1;
      },
      indexAllOf: function(myArray, searchTerm, property) {
        var ai = [];
        for (var i = 0; i < myArray.length; i++) {
          if (myArray[i][property] === searchTerm) ai.push(i);
        }
        return ai;
      },
      lookup: function(myArray, searchTerm, property, firstOnly) {
        var found = [];
        var i = myArray.length;
        while (i--) {
          if (myArray[i][property] === searchTerm) {
            found.push(myArray[i]);
            if (firstOnly) break; //if only the first 
          }
        }
        return found;
      },
      exclude: function(myArray, searchTerm, property, firstOnly = false) {
        var found = [];
        var i = myArray.length;
        while (i--) {
          if (myArray[i][property] !== searchTerm) {
            found.push(myArray[i]);
            if (firstOnly) break; //if only the first 
          }
        }
        return found;
      },
      lookupAll: function(myArray, searchTerm, property) {
        return this.lookup(myArray, searchTerm, property, false);
      },
      arrSum: function(arr, selectorProp, selectorValue, numProp) {
        // get the summary (total) of any object array, assumes number
        function isSumMatch(item, index, arr) {
          return item[1][selectorProp] == selectorValue;
        }
        const arrSum = Object.entries(arr)
          .filter(isSumMatch)
          .map(item => item[1][numProp])
          .reduce((partial_sum, a) => partial_sum + a, 0);
        return arrSum;
      }
    };
    myApp.data = myApp.data || {
      items: rawdata
    };
    // could also do:
    //myApp.data = myApp.data || {};
    //myApp.data.items = myApp.data.items || rawdata;
    
    // add a function, could be in above also
    myApp.funcs.formatData = function(data) {
      let brandnames = [];
      let itemnames = [];
      let outlets = [];
      data.forEach(element => {
        //taking brandname which do not have bradname===NA
        if (brandnames.indexOf(element.brandname) == -1 && (element.brandname) !== "NA") {
          brandnames.push(element.brandname);
        }
        //taking itemname which do not have bradname===NA
        if (itemnames.indexOf(element.itemname) == -1 && (element.itemname) !== "NA") {
          itemnames.push(element.itemname);
        }
        if (outlets.indexOf(element.outlet) == -1) {
          outlets.push(element.outlet);
        }
      });
      return {
        //data: data,
        brandnames: brandnames,
        itemnames: itemnames,
        outlets: outlets,
      };
    };
    
    let renderHeader = function(data, targetTable) {
      let headId = targetTable.id + "-theadid";
      let thead = document.createElement("thead");
      thead.setAttribute("id", headId);
      let headerRow = document.createElement("tr");
      let headerInst = 0;
      let rowClass = headId + "-" + headerInst;
      headerRow.setAttribute("id", headId);
      headerRow.classList.add(rowClass);
      let th = document.createElement("th");
      // first header row
      th = document.createElement("th");
      th.innerHTML = "Brand Name";
      th.classList.add("text-center");
      headerRow.appendChild(th);
    
      th = document.createElement("th");
      th.colSpan = 2;
      th.innerHTML = "Total";
      th.classList.add("text-center");
      headerRow.appendChild(th);
      // first header row - outlets names
      data.formatedData.outlets.forEach(outlet => {
        th = document.createElement("th");
        th.colSpan = 2;
        th.setAttribute("data-outlet", outlet);
        th.innerHTML = outlet; // populating outlet 
        th.classList.add("text-center");
        headerRow.appendChild(th);
      });
      thead.appendChild(headerRow);
    
      /* entery header row */
      headerRow = document.createElement("tr");
      th = document.createElement("th");
      th.innerHTML = "";
      headerRow.appendChild(th);
      let i = 0;
      // entery header row
      for (i; i < data.formatedData.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);
      }
      thead.appendChild(headerRow);
      let oh = targetTable.getElementsByTagName('thead')[0];
      oh.parentNode.replaceChild(thead, oh);
      myApp.data.origHead = targetTable.getElementsByTagName('thead')[0];
      return headId;
    };
    
    let renderGrandTotal = function(data, targetTable, origHead) {
      let headerRow = document.createElement("tr");
      let th = document.createElement("th");
      th.innerHTML = "Total";
      th.classList.add("text-center");
      headerRow.appendChild(th);
    
      let el1 = 0;
      data.formatedData.outlets.forEach(element => {
        th = document.createElement("th");
        th.innerHTML = data.outletWiseTotal[element].toLocaleString('en-IN');
        th.classList.add("text-right");
        headerRow.appendChild(th);
        if (element.outlet == element) {
          el1 = element.netAmount;
        }
        th = document.createElement("th");
        th.innerHTML = data.outletWiseNetamount[element].toLocaleString('en-IN') || 0;
        th.classList.add("text-right");
        headerRow.appendChild(th);
      });
      th = document.createElement("th");
      th.innerHTML = data.grandNetAmount.toLocaleString('en-IN');
      th.classList.add("text-right");
      headerRow.insertBefore(th, headerRow.children[1]);
    
      th = document.createElement("th");
      th.innerHTML = data.grandTotal.toLocaleString('en-IN');
      th.classList.add("text-right");
      headerRow.insertBefore(th, headerRow.children[1]);
      origHead.appendChild(headerRow);
    };
    let getTotals = function(data) {
      data.outletWiseTotal = {};
      data.outletWiseNetamount = {};
      let na = "NA";
      let bn = "brandname";
      let num = 'netamount';
      let notJustOne = false;
      data.grandTotal = myApp.funcs.arrSum(myApp.funcs.exclude(data.items, na, bn, notJustOne), 'transactionType', 'TransferIn', num);
      data.grandNetAmount = myApp.funcs.arrSum(myApp.funcs.lookupAll(data.items, "NA", bn), 'transactionType', "Sales", num);
      data.formatedData.outlets.forEach(element => {
        data.outletWiseTotal[element] = 0;
        let myOutlet = myApp.funcs.lookupAll(data.items, element, "outlet");
        let notNA = myApp.funcs.exclude(myOutlet, na, bn);
        let justNA = myApp.funcs.lookupAll(myOutlet, na, bn);
        data.outletWiseTotal[element] = myApp.funcs.arrSum(notNA, 'outlet', element, num);
        data.outletWiseNetamount[element] = myApp.funcs.arrSum(justNA, 'transactionType', "Sales", num);
      });
      return data;
    };
    
    let findHeader = function(origHead, searchText) {
      let headers = origHead.getElementsByTagName("tr")[0]
        .getElementsByTagName("th");
    
      let found;
      let i = 0;
      for (i; i < headers.length; i++) {
        if (headers[i].dataset.outlet == searchText) {
          found = headers[i];
          break;
        }
      }
    
      return {
        head: headers,
        index: i,
        outletHeader: found
      };
    };
    
    function getHeadByCell(headerRow, cell) {
      var idx = $(cell).index(),
        th,
        th_colSpan = 0;
      let i = 0;
      for (i; i < headerRow.cells.length; i++) {
        th = headerRow.cells[i];
        th_colSpan += th.colSpan;
        let isThing = (th_colSpan >= (idx + cell.colSpan));
        if (th_colSpan >= (idx + cell.colSpan)) {
          break;
        }
      }
      return th;
    }
    
    let renderBrandDetailRow = function(rowdata, tblBody, brandname, brandClass) {
      // render stuff like Bakery FG
      let r = 0;
      for (r; r < rowdata.length; r++) {
        let row = document.createElement("tr");
        row.classList.add("collapse", brandClass);
        let td = document.createElement("td");
        td.classList.add("text-center");
        td.innerHTML = brandname;
        row.appendChild(td);
        // item name
        td = document.createElement("td");
        td.classList.add("text-center");
        td.colSpan = 2;
        td.innerHTML = rowdata[r]["itemname"];
        row.appendChild(td);
        // punch in empty column data first
        let groupOutletsCount = myApp.data.formatedData.outlets.length;
        for (let c = 0; c < (groupOutletsCount * 2); c++) {
          td = document.createElement("td");
          td.classList.add("text-right");
          row.appendChild(td);
        }
        let origHead = myApp.data.origHead;
        let found = findHeader(origHead, rowdata[r].outlet);
        let testRow = origHead.getElementsByTagName("tr")[1];
        let fr = 0;
        for (fr; fr < testRow.getElementsByTagName("th").length; fr++) {
          let mycell = testRow.getElementsByTagName("th")[fr];
          let ath = getHeadByCell(origHead.getElementsByTagName("tr")[0], mycell);
          if (ath == found.outletHeader) break;
        }
        // now we have the header that matches, put the data in the right place
        row.getElementsByTagName("td")[fr].innerHTML = rowdata[r]["netamount"].toLocaleString('en-IN');
        tblBody.appendChild(row);
      }
    };
    let renderTable = function(data) {
      let tbl = document.getElementById("ConsumptionTable");
      tbl.classList.add("table", "table-striped", "table-bordered", "table-hover");
      let headId = renderHeader(data, tbl);
      let origHead = document.getElementById(headId);
      let tbody = document.createElement("tbody");
    
      let headerInst = 0;
      let rowClass = headId + "-" + headerInst;
      renderGrandTotal(data, tbl, origHead);
      let collapseClass = 0;
      data.formatedData.brandnames.forEach(element => {
        let brandSum = myApp.funcs.arrSum(data.items, 'brandname', element, "netamount");
        let row = document.createElement("tr");
        let td = document.createElement("td");
        let brandClass = "multi-collapse-" + collapseClass;
        td.innerHTML = '<span><i class="fas fa-plus expand-child-group" data-toggle="collapse" data-target="' + '.' + brandClass + '"></i>&nbsp</span> ' + element;
        row.appendChild(td);
        data.formatedData.outlets.forEach(outlet => {
          let outletSum = myApp.funcs.arrSum(myApp.data.items, 'outlet', outlet, 'netamount');
          data.olWiseSalesPercentage = (brandSum / outletSum) * 100 || 0;
          td = document.createElement("td");
          td.innerHTML = brandSum.toLocaleString('en-IN');
          td.classList.add("text-right");
          row.appendChild(td);
          td = document.createElement("td");
          td.innerHTML = data.olWiseSalesPercentage.toFixed(2) + "%";
          td.classList.add("text-right");
          row.appendChild(td);
        });
        data.totalSalesPercentage = (brandSum / data.grandTotal) * 100;
        const totalSalesPercentageFix = data.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 = brandSum.toLocaleString('en-IN');
        td.classList.add("text-right");
        row.insertBefore(td, row.children[1]);
        tbody.appendChild(row);
        let brandData = myApp.funcs.lookupAll(myApp.data.items, element, 'brandname');
        renderBrandDetailRow(brandData, tbody, element, brandClass);
        collapseClass++;
      });
      tbl.appendChild(tbody);
    };
    
    $('#things-i-did').find('.list-group').toggleClass('hidden', true);
    myApp.data.formatedData = myApp.funcs.formatData(myApp.data.items);
    getTotals(myApp.data);
    renderTable(myApp.data);
    
    let cttbl = document.getElementById('ConsumptionTable');
    cttbl.addEventListener('click', function(event) {
      let myExp = "expand-child-group";// detail row class
      if (event.target.classList.contains(myExp)) {
        let myAttr = event.target.dataset.target;
        //console.log(myAttr);
      }
    }, false);
    .expand-child-group {
      color: green;
      cursor: pointer;
    }
    
    .identify-me {
      background-color: lime;
    }
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
    
    <div id="things-i-did">
      <h5>Things I did: <button class="btn btn-primary btn-sm" type="button" data-toggle="collapse" data-target="#collapseChanges" aria-expanded="false" aria-controls="collapseChanges">
        Toggle changes visible
      </button></h5>
      <div id="collapseChanges" class="collapse">
        <ul class="list-group">
          <li class="list-group-item">Added this silly toggle list</li>
          <li class="list-group-item">Added a lot of missing semi-colons</li>
          <li class="list-group-item">Remove obvious comments "do calculation"</li>
          <li class="list-group-item">Consolidate the: <code>td.classlist.add("my-class");
    td.classlist.add("my-other-class");</code> to an array/list: <code>td.classlist.add("my-class","my-other-class");</code></li>
          <li class="list-group-item">Several "undefined" variables used, removed or defined with <code>let mything =</code></li>
          <li class="list-group-item">Clarify several variables used</li>
          <li class="list-group-item">Remove several "unused" variables</li>
          <li class="list-group-item">added base to parseInt functions</li>
          <li class="list-group-item">Used Event listener for click <code>cttbl.addEventListener('click', function(event) {</code></li>
          <li class="list-group-item">change <code>td = something</code> to <code>th = something</code> variable to clarify intent</li>
          <li class="list-group-item">Removed <code>id="test"</code>, duplicate ID's are invalid</li>
          <li class="list-group-item">Created an object <code>var myApp = myApp || {};</code> to hold all the stuff <i>(function, calculation data, globals)</i> and avoid global variables</li>
          <li class="list-group-item">functions for each detail row under proper header</li>
        </ul>
      </div>
    </div>
    <div align="center" class="table table-responsive">
      <table id="ConsumptionTable">
        <thead></thead>
      </table>
    </div>

    【讨论】:

      【解决方案6】:

      请使用 DataTables 检查以下解决方案。

      https://codepen.io/nbaua/pen/WBNQVE

      HTML

      <div style="margin:20px">
      <table id="example" class="display" style="width:80%">
              <thead>
                  <tr>
                      <th></th>
                      <th>Outlet</th>
                      <th>Brand Name</th>
                      <th>Item Name</th>
                      <th>Transaction Type</th>
                      <th>Net Amount</th>
                  </tr>
              </thead>
      
          </table></div>
      

      CSS

      td.details-control {
        width:32px;
        height:32px;
          background: url('https://image.flaticon.com/icons/png/24/149/149145.png') no-repeat center center;
          cursor: pointer;
      }
      tr.shown td.details-control {
        width:32px;
        height:32px;
          background: url('https://image.flaticon.com/icons/png/24/149/149147.png') no-repeat center center;
      }
      

      JAVASCRIPT

          function format ( d ) {
          // `d` is the original data object for the row
        //create the tamplate as per your wish
          return '<table cellpadding="5" cellspacing="0" border="0" style="padding-left:50px;">'+
              '<tr>'+
                  '<td>Outlet:</td>'+
                  '<td>'+d.outlet +'</td>'+
              '</tr>'+
              '<tr>'+
                  '<td>Brand Name:</td>'+
                  '<td>'+d.brandname +'</td>'+
              '</tr>'+
              '<tr>'+
                  '<td>Transaction Type:</td>'+
                  '<td>And any further details here...</td>'+
              '</tr>'+
          '</table>';
      }
      var groupColumn = 2; //Group by column index
      $(document).ready(function() {
          var table = $('#example').DataTable( {
      
            "drawCallback": function ( settings ) {
                  var api = this.api();
                  var rows = api.rows( {page:'current'} ).nodes();
                  var last=null;
      
                  api.column(groupColumn, {page:'current'} ).data().each( function ( group, i ) {
                      if ( last !== group ) {
                          $(rows).eq( i ).before(
                              '<tr class="group"><td colspan="5"><h3>'+group+'</h3></td></tr>'
                          );
      
                          last = group;
                      }
                  } );
              },
      
              "data": [{
          "outlet": "JAYANAGAR",
          "brandname": "Bakery FG",
          "itemname": "Khara Boondhi-L",
          "transactionType": "TransferIn",
          "netamount": 980
        },
        ....... 1000 OTHER ITEMS 
        {
          "outlet": "MALLESHWARAM",
          "brandname": "NA",
          "itemname": "NA",
          "transactionType": "Sales",
          "netamount": 92141
        }
      ],
              "columns": [
                  {
                      "className":      'details-control',
                      "data":           null,
                      "defaultContent": ''
                  },
                  { "data": "outlet" }, //simply remove this columns if you don't require them in outer row
                  //{ "data": "brandname" },
                  { "data": "itemname" },
                  { "data": "transactionType" },
                  { "data": "netamount" }
              ],
              "order": [[1, 'asc']]
          } );
      
          // Add event listener for opening and closing details
          $('#example tbody').on('click', 'td.details-control', function () {
              var tr = $(this).closest('tr');
              var row = table.row( tr );
      
              if ( row.child.isShown() ) {
                  // This row is already open - close it
                  row.child.hide();
                  tr.removeClass('shown');
              }
              else {
                  // Open this row
                  row.child( format(row.data()) ).show();
                  tr.addClass('shown');
              }
          } );
      } );
      

      【讨论】:

      • 嘿,这不是我想要做的,你改变了我的 HTML 表格的整个结构
      • 我已经有我 hvlave 创建的表结构我只想在品牌名称中创建一个具有项目名称和与品牌名称相同结构的行...每个品牌名称都有一些我想展示的项目他们在品牌内作为点击加号图标的行
      • 如果您先看代码并理解它,您将能够按照您的要求进行操作。 SO 用于在您遇到困难时寻求帮助。不是为了完成你的事情。
      • 不,先生,我不是在寻找完整的解决方案,因为在您的代码中,您所做的与我的要求完全相反,您将项目填充为标题,然后单击显示完全相反的品牌的出口,我的问题是我如何在他们的品牌中填充项目名称,你可以看到每个项目都有品牌名称
      • @NBuaa 不要告诉用户“标记为答案,如果它对你有用,以帮助社区的其他成员。”,绝对不在答案之内。他们会在他们想要的时候做,如果他们愿意的话
      猜你喜欢
      • 1970-01-01
      • 2017-11-06
      • 1970-01-01
      • 2015-01-02
      • 1970-01-01
      • 2016-12-07
      • 2019-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多