Как заставить HTML-таблицу расширяться при клике?

Я рендеринг HTML-таблицы с помощью JavaScript. Я сделал таблицу успешно, но теперь у меня есть одно требование, чтобы показать некоторые новые данные в строке, как по щелчку развернуть строку

Функциональность таблицы:

  • Я заполняю свой стол. У некоторых брендов в каждом бренде есть несколько предметов, которые я хочу показать, когда на бренд нажимают.
  • Я почти создал таблицу, но не смог создать расширяемую строку
  • Мой столбец также заполняет неправильные данные

В своем коде я прокомментировал все строки, что я делаю в какой строке

Проблемы, с которыми я сталкиваюсь

  • Я уже прокомментировал строку, где я вычисляю netamount для заполнения внутри tbody как мудрый бренд GRN entery но это вызывает проблему

Я создал два фрагмента кода, один из которых представляет собой полностью статический 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="#" onclick="location.href='https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css'; return false;">
<link rel="stylesheet" type="text/css" href="#" onclick="location.href='https://use.fontawesome.com/releases/v5.6.3/css/all.css'; return false;">

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

Ответы

Ответ 1

Сделайте это таким образом, следуйте СУХОЙ и модульной структуре, чтобы сделать ее более удобочитаемой и удобной в обслуживании.

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

Я предлагаю вам использовать DataTables.

DataTables предлагает богатый API для рендеринга данных строк, отображения/скрытия столбцов, поиска/фильтрации, подкачки страниц и т.д. Его можно стилизовать с помощью пользовательского интерфейса jQuery или Bootstrap или собственного брендинга. В отличие от написания вашей собственной логики отображения таблиц, библиотеки DataTables бесплатны и чрезвычайно гибки.

Смотрите: https://datatables.net/examples/api/row_details.html.

Ответ 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

Чтобы достичь ожидаемого результата, используйте нижеприведенную опцию создания новой таблицы внутри кликаемого тд

  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>

Ответ 5

Как реализовать переключение слайдов таблицы...

Вероятно, проще всего поместить обработчик кликов на всю таблицу,.stopPropagation() и проверить, что было нажато.

Если щелкнуть тд в ряду с colspan, закройте в нем букву p. Если это не тд в ряду с colspan, затем закройте, затем переключите следующую строку p.

По сути, это обернуть весь ваш письменный контент в элемент внутри tds, так как вы никогда не захотите сдвинуть вверх td или tr или форма таблицы изменится!

Что-то вроде:

$(function() {

      // Initially hide toggleable content
    $("td[colspan=3]").find("p").hide();

      // Click handler on entire table
    $("table").click(function(event) {

          // No bubbling up
        event.stopPropagation();

        var $target = $(event.target);

          // Open and close the appropriate thing
        if ( $target.closest("td").attr("colspan") > 1 ) {
            $target.slideUp();
        } else {
            $target.closest("tr").next().find("p").slideToggle();
        }                    
    });
});​

Попробуйте это с этим примером jsFiddle.

... и попробуйте этот jsFiddle, показывающий реализацию переключателя + - -.

HTML просто должен иметь чередующиеся строки из нескольких тд, а затем строку с тд colspan больше 1. Очевидно, что вы можете легко настроить специфику.

HTML будет выглядеть примерно так:

<table>
    <tr><td><p>Name</p></td><td><p>Age</p></td><td><p>Info</p></td></tr>
    <tr><td colspan="3"><p>Blah blah blah blah blah blah blah.</p>
    </td></tr>

    <tr><td><p>Name</p></td><td><p>Age</p></td><td><p>Info</p></td></tr>
    <tr><td colspan="3"><p>Blah blah blah blah blah blah blah.</p>
    </td></tr>

    <tr><td><p>Name</p></td><td><p>Age</p></td><td><p>Info</p></td></tr>
    <tr><td colspan="3"><p>Blah blah blah blah blah blah blah.</p>
    </td></tr>    
</table>​

Ответ 6

Почти чистый пример решения 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 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>

Ответ 7

Пожалуйста, проверьте следующее решение, используя 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');
        }
    } );
} );