# Documentation v8.0.38

Preview Downloads Purchase
DataTables is a plug-in for the jQuery Javascript library. It is a highly flexible tool, based upon the foundations of progressive enhancement, and will add advanced interaction controls to any HTML table. For more info see the official site.

# Sub Datatable Example

This example shows the DataTables table with an expandable row. The sub-rows data are generated by using DataTable's template methods with simple JS data objects that can either be generated locally or retrieved from an API endpoint.

Order ID | Created | Customer | Total | Profit | Status |
--- | --- | --- | --- | --- | --- | ---
Product name Product description | Cost 1 | Qty 1 | Total name | On hand 32 |
#XGT-346 | 30 March 2022, 3:21 pm | Emma Smith | $630.00 | $86.70 | Pending |
#YHD-047 | 30 March 2022, 2:30 pm | Melody Macy | $25.00 | $4.20 | Confirmed |
#SRR-678 | 30 March 2022, 11:22 am | Max Smith | $1,630.00 | $203.90 | Pending |
#PXF-534 | 29 March 2022, 3:22 pm | Sean Bean | $119.00 | $12.00 | Shipped |
#XGD-249 | 28 March 2022, 3:22 pm | Brian Cox | $660.00 | $52.26 | Shipped |
#SKP-035 | 27 March 2022, 3:22 pm | Brian Cox | $290.00 | $29.00 | Rejected |

    <table class="table align-middle table-row-dashed fs-6 gy-4" id="kt_docs_datatable_subtable">
     <!--begin::Table head-->
     <thead>
      <!--begin::Table row-->
      <tr class="text-start text-gray-400 fw-bolder fs-7 text-uppercase gs-0">
       <th class="min-w-100px">Order ID</th>
       <th class="text-end min-w-100px">Created</th>
       <th class="text-end min-w-150px">Customer</th>
       <th class="text-end min-w-100px">Total</th>
       <th class="text-end min-w-100px">Profit</th>
       <th class="text-end min-w-50px">Status</th>
       <th class="text-end"></th>
      </tr>
      <!--end::Table row-->
     </thead>
     <!--end::Table head-->

     <!--begin::Table body-->
     <tbody class="fw-bolder text-gray-600">
      <!--begin::SubTable template-->
      <tr data-kt-docs-datatable-subtable="subtable_template" class="d-none">
       <td colspan="2">
        <div class="d-flex align-items-center gap-3">
         <a href="#" class="symbol symbol-50px bg-secondary bg-opacity-25 rounded">
          <img src="/assets/media/stock/ecommerce/" alt="" data-kt-docs-datatable-subtable="template_image" />
         </a>
         <div class="d-flex flex-column text-muted">
          <a href="#" class="text-dark text-hover-primary fw-bolder" data-kt-docs-datatable-subtable="template_name">Product name</a>
          <div class="fs-7" data-kt-docs-datatable-subtable="template_description">Product description</div>
         </div>
        </div>
       </td>
       <td class="text-end">
        <div class="text-dark fs-7">Cost</div>
        <div class="text-muted fs-7 fw-bolder" data-kt-docs-datatable-subtable="template_cost">1</div>
       </td>
       <td class="text-end">
        <div class="text-dark fs-7">Qty</div>
        <div class="text-muted fs-7 fw-bolder" data-kt-docs-datatable-subtable="template_qty">1</div>
       </td>
       <td class="text-end">
        <div class="text-dark fs-7">Total</div>
        <div class="text-muted fs-7 fw-bolder" data-kt-docs-datatable-subtable="template_total">name</div>
       </td>
       <td class="text-end">
        <div class="text-dark fs-7 me-3">On hand</div>
        <div class="text-muted fs-7 fw-bolder" data-kt-docs-datatable-subtable="template_stock">32</div>
       </td>
       <td></td>
      </tr>
      <!--end::SubTable template-->

      <tr>
       <!--begin::Order ID-->
       <td>
        <a href="#" class="text-dark text-hover-primary">#XGT-346</a>
       </td>
       <!--end::Order ID-->

       <!--begin::Crated date-->
       <td class="text-end">
        10 Nov 2021, 10:30 am
       </td>
       <!--end::Created date-->

       <!--begin::Customer-->
       <td class="text-end">
        <a href="" class="text-dark text-hover-primary">Emma Smith</a>
       </td>
       <!--end::Customer-->

       <!--begin::Total-->
       <td class="text-end">
        $630.00
       </td>
       <!--end::Total-->

       <!--begin::Profit-->
       <td class="text-end">
        <span class="text-dark fw-bolder">$86.70</span>
       </td>
       <!--end::Profit-->

       <!--begin::Status-->
       <td class="text-end">
        <span class="badge py-3 px-4 fs-7 badge-light-primary">Confirmed</span>
       </td>
       <!--end::Status-->

       <!--begin::Actions-->
       <td class="text-end">
        <button type="button" class="btn btn-sm btn-icon btn-light btn-active-light-primary toggle h-25px w-25px"
         data-kt-docs-datatable-subtable="expand_row">
         <span class="svg-icon svg-icon-3 m-0 toggle-off">...</span>
         <span class="svg-icon svg-icon-3 m-0 toggle-on">...</span>
        </button>
       </td>
       <!--end::Actions-->
      </tr>

       ...
     </tbody>
     <!--end::Table body-->
    </table>

    var table;
    var datatable;
    var template;

    // Private methods
    const initDatatable = () => {
     // Set date data order
     const tableRows = table.querySelectorAll('tbody tr');

     tableRows.forEach(row => {
      const dateRow = row.querySelectorAll('td');
      const realDate = moment(dateRow[1].innerHTML, "DD MMM YYYY, LT").format(); // select date from 2nd column in table

      // Skip template
      if (!row.closest('[data-kt-docs-datatable-subtable="subtable_template"]')) {
       dateRow[1].setAttribute('data-order', realDate);
       dateRow[1].innerText = moment(realDate).fromNow();
      }
     });

     // Get subtable template
     const subtable = document.querySelector('[data-kt-docs-datatable-subtable="subtable_template"]');
     template = subtable.cloneNode(true);
     template.classList.remove('d-none');

     // Remove subtable template
     subtable.parentNode.removeChild(subtable);

     // Init datatable --- more info on datatables: https://datatables.net/manual/
     datatable = $(table).DataTable({
      "info": false,
      'order': [],
      "lengthChange": false,
      'pageLength': 6,
      'ordering': false,
      'paging': false,
      'columnDefs': [
       { orderable: false, targets: 0 }, // Disable ordering on column 0 (checkbox)
       { orderable: false, targets: 6 }, // Disable ordering on column 6 (actions)
      ]
     });

     // Re-init functions on every table re-draw -- more info: https://datatables.net/reference/event/draw
     datatable.on('draw', function () {
      resetSubtable();
      handleActionButton();
     });
    }

    // Subtable data sample
    const data = [
     {
      image: '76',
      name: 'Go Pro 8',
      description: 'Latest  version of Go Pro.',
      cost: '500.00',
      qty: '1',
      total: '500.00',
      stock: '12'
     },

     ...
    ];

    // Handle action button
    const handleActionButton = () => {
     const buttons = document.querySelectorAll('[data-kt-docs-datatable-subtable="expand_row"]');

     // Sample row items counter --- for demo purpose only, remove this variable in your project
     const rowItems = [4, 1, 5, 1, 4, 2];

     buttons.forEach((button, index) => {
      button.addEventListener('click', e => {
       e.stopImmediatePropagation();
       e.preventDefault();

       const row = button.closest('tr');
       const rowClasses = ['isOpen', 'border-bottom-0'];

       // Get total number of items to generate --- for demo purpose only, remove this code snippet in your project
       const demoData = [];
       for (var j = 0; j < rowItems[index]; j++) {
        demoData.push(data[j]);
       }
       // End of generating demo data

       // Handle subtable expanded state
       if (row.classList.contains('isOpen')) {
        // Remove all subtables from current order row
        while (row.nextSibling && row.nextSibling.getAttribute('data-kt-docs-datatable-subtable') === 'subtable_template') {
         row.nextSibling.parentNode.removeChild(row.nextSibling);
        }
        row.classList.remove(...rowClasses);
        button.classList.remove('active');
       } else {
        populateTemplate(demoData, row);
        row.classList.add(...rowClasses);
        button.classList.add('active');
       }
      });
     });
    }

    // Populate template with content/data -- content/data can be replaced with relevant data from database or API
    const populateTemplate = (data, target) => {
     data.forEach((d, index) => {
      // Clone template node
      const newTemplate = template.cloneNode(true);

      // Stock badges
      const lowStock = `<div class="badge badge-light-warning">Low Stock</div>`;
      const inStock = `<div class="badge badge-light-success">In Stock</div>`;

      // Select data elements
      const image = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_image"]');
      const name = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_name"]');
      const description = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_description"]');
      const cost = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_cost"]');
      const qty = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_qty"]');
      const total = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_total"]');
      const stock = newTemplate.querySelector('[data-kt-docs-datatable-subtable="template_stock"]');

      // Populate elements with data
      const imageSrc = image.getAttribute('src');
      image.setAttribute('src', imageSrc + d.image + '.gif');
      name.innerText = d.name;
      description.innerText = d.description;
      cost.innerText = d.cost;
      qty.innerText = d.qty;
      total.innerText = d.total;
      if (d.stock > 10) {
       stock.innerHTML = inStock;
      } else {
       stock.innerHTML = lowStock;
      }

      // New template border controller
      // When only 1 row is available
      if (data.length === 1) {
       let borderClasses = ['rounded', 'rounded-end-0'];
       newTemplate.querySelectorAll('td')[0].classList.add(...borderClasses);
       borderClasses = ['rounded', 'rounded-start-0'];
       newTemplate.querySelectorAll('td')[4].classList.add(...borderClasses);

       // Remove bottom border
       newTemplate.classList.add('border-bottom-0');
      } else {
       // When multiple rows detected
       if (index === (data.length - 1)) { // first row
        let borderClasses = ['rounded-start', 'rounded-bottom-0'];
        newTemplate.querySelectorAll('td')[0].classList.add(...borderClasses);
        borderClasses = ['rounded-end', 'rounded-bottom-0'];
        newTemplate.querySelectorAll('td')[4].classList.add(...borderClasses);
       }
       if (index === 0) { // last row
        let borderClasses = ['rounded-start', 'rounded-top-0'];
        newTemplate.querySelectorAll('td')[0].classList.add(...borderClasses);
        borderClasses = ['rounded-end', 'rounded-top-0'];
        newTemplate.querySelectorAll('td')[4].classList.add(...borderClasses);

        // Remove bottom border on last row
        newTemplate.classList.add('border-bottom-0');
       }
      }

      // Insert new template into table
      const tbody = table.querySelector('tbody');
      tbody.insertBefore(newTemplate, target.nextSibling);
     });
    }

    // Reset subtable
    const resetSubtable = () => {
     const subtables = document.querySelectorAll('[data-kt-docs-datatable-subtable="subtable_template"]');
     subtables.forEach(st => {
      st.parentNode.removeChild(st);
     });

     const rows = table.querySelectorAll('tbody tr');
     rows.forEach(r => {
      r.classList.remove('isOpen');
      if (r.querySelector('[data-kt-docs-datatable-subtable="expand_row"]')) {
       r.querySelector('[data-kt-docs-datatable-subtable="expand_row"]').classList.remove('active');
      }
     });
    }

### Explore

### Metronic Licenses

License FAQs
Regular License
For single end product used by you or one client
$ 39
Extended License
For single SaaS app with paying users
$ 969
Custom License
Reach us for custom license offers.
Contact Us
Buy Now

### Metronic Demos

Demo 1
Demo 2
Demo 3
Demo 4
Demo 5
Demo 6
Demo 7
Demo 8
Demo 9
Demo 10
Demo 11
Demo 12
Demo 13
Demo 14
Demo 15
Demo 16
Demo 17
Demo 18
Demo 19
Demo 20
Demo 21
Demo 22
Coming soon
Coming soon

##### Learn & Get Inspired

## Support at devs.keenthemes.com

Join our developers community to find answer to your question and help others. FAQs
Get Support
Documentation & Videos
From guides and video tutorials, to live demos and code examples to get started.
Plugins & Components
Check out our 300+ in-house components and customized 3rd-party plugins.
Layout Builder
Build your layout, preview it and export the HTML for server side integration.
Metronic Downloads
Download your prefered framework and demo with one click.
What's New
Latest features and improvements added with our users feedback in mind.
Buy now