Overview

DataTable component based on datatables.net with advanced instructions.

Reference

Instance Methods
Name Description
public constructor() Create a new instance of the Datatable class.
Parameters:
  • element: string|HTMLTableElement|JQuery
    HTMLTableElement selector, element, or JQuery object.
  • options: DatatableOptions
    An object with the following custom options inherited from DataTables.Settings.
    • firstAjax?: boolean
      If asynchronous mode (options.ajax) is enabled, whether to request table data remotely first. If true, request table data first; if false, do not request table data until the Datatable.reload method is called. Default is true.
    • locale?: 'en'|'ja'
      Locale of the displayed text. Default is English (en).
The following values are used as defaults for the options.
  • scrollX: boolean true
  • dom: string `<'row'<'col-12 dataTables_pager'p>><'row'<'col-12'tr>><'row'<'col-12 dataTables_pager'p>>`
  • pageLength: number 30
  • searchDelay: number 500
  • processing: boolean true
  • serverSide: boolean If the ajax option is present, it is automatically set to true.
  • fnServerParams: (aoData: any) => If Ajax is enabled, the following data is sent to the server.
    • start: number Starting point of the current data set (0 index base, i.e., 0 is the first record).
    • length: number The number of records the table can display.
    • order: string Columns to be ordered.
    • dir: string Direction of sorting. It will be asc or desc, indicating ascending or descending order, respectively.
    • draw: number A drawing counter. Used to ensure that responses from the server are drawn in sequence.
                    import {components} from 'metronic-extension';

// Initialize DataTable.
const myTable = new components.Datatable(document.getElementById('myTable'), {
  columnDefs: [
    {targets: 0, data: 'name'},
    {targets: 1, data: 'position'},
  ]
});

// Retrieve table data from the server via Ajax request
const myTableWithAjax = new components.Datatable(document.getElementById('myTableWithAjax'), {
  ajax: {
    url: '/api/persons/pages'
  },
  columnDefs: [
    {targets: 0, data: 'name'},
    {targets: 1, data: 'position'},
  ]
});
                  
public reload() Reload the table data from the Ajax data source.
Parameters:
  • resetPaging: boolean
    Reset (default action or true) or hold the current paging position (false).
Return:
  • Promise<any> JSON data returned by the server.
public adjustColumns() Adjust column layout.
public filter() Filter row by the specified string.
Parameters:
  • columnSelector: any
    Column selector. See here for more information.
  • input: string
    Search string to apply to the table.
  • regex: boolean
    Whether to treat input as a regular expression (true) or not (default is false).
                        <table id="myTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Airi Satou</td>
      <td>Accountant</td>
    </tr>
    <tr>
      <td>Angelica Ramos</td>
      <td>Chief Executive Officer (CEO)</td>
    </tr>
  </tbody>
</table>
                      
                        import {components} from 'metronic-extension';

// Initialize DataTable.
const myTable = new components.Datatable(document.getElementById('myTable'), {
  columnDefs: [
    {targets: 0, name: 'name'},
    {targets: 1, name: 'position'},
  ],
});

// Search by column position.
myTable.filter(1, 'CEO');

// Search by column name.
myTable.filter('position:name', 'CEO');
                      
public getContainer() Returns a table wrapper element.
Parameters:
  • asHtmlElement: boolean
    If true, get it as an HTMLElement, if false, get it as a jQuery object. Default is false.
Return:
  • JQuery|HTMLElement Table wrapper element.
public getFilterContainer() Returns a table filter container element.
Parameters:
  • asHtmlElement: boolean
    If true, get it as an HTMLElement, if false, get it as a jQuery object. Default is false.
Return:
  • JQuery|HTMLElement|null Filter container element.
public createRow() Create a row.
Parameters:
  • data: any
    Data to use for the new row. This may be an array, object, Javascript object instance or a tr element. If a data structure is used (i.e. array or object) it must be in the same format as the other data in the table (i.e. if your table uses objects, pass in an object with the same properties here!).
  • paging: boolean
    The type of drawing after the row is added. If true, paging is reset to the first page; if false Paging is not reset and the current page is displayed. Default is true.
Return:
  • Datatable
                        <table id="myTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Airi Satou</td>
      <td>Accountant</td>
    </tr>
    <tr>
      <td>Angelica Ramos</td>
      <td>Chief Executive Officer (CEO)</td>
    </tr>
  </tbody>
</table>
                      
                        import {components} from 'metronic-extension';

// Initialize DataTable.
const myTable = new components.Datatable(document.getElementById('myTable'), {
  columnDefs: [
    {targets: 0, data: 'name'},
    {targets: 1, data: 'position'},
  ],
});

// Add object as a new row.
myTable.createRow({name: 'Ashton Cox', position: 'Junior Technical Author'});

// Add HTML element as a new row.
const row = document.createElement('tr');
row.insertAdjacentHTML('afterbegin', '<td>Bradley Greer</td><td>Software Engineer</td>');
myTable.createRow(row);
                      
public deleteRow() Delete row.
Parameters:
  • rowSelector: any
    Row selector. See here for more information.
Return:
  • Datatable
                        <table id="myTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>#</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Airi Satou</td>
      <td>Accountant</td>
      <td><button data-on-delete class="btn btn-primary">Delete</button></td>
    </tr>
    <tr>
      <td>Angelica Ramos</td>
      <td>Chief Executive Officer (CEO)</td>
      <td><button data-on-delete class="btn btn-primary">Delete</button></td>
    </tr>
  </tbody>
</table>
                      
                        import {components} from 'metronic-extension';

// Initialize DataTable.
const myTable = new components.Datatable(document.getElementById('myTable'), {
  columnDefs: [
    {targets: 0, data: 'name'},
    {targets: 1, data: 'position'},
    {targets: 2, data: 'actions'},
  ],
});

// Delete at specified position; the second row is deleted.
myTable.deleteRow(1);

// Specify a row element to delete.
$('#myTable tbody').on('click', '[data-on-delete]', evnt => {
  // Get selection row.
  const row = evnt.currentTarget.closest('tr');

  // Delete row.
  myTable.deleteRow(row);
});
                      
public updateRow() Update row.
Parameters:
  • rowSelector: any
    Row selector. See here for more information.
  • data: any[]|object
    Data source object for the data source of the row. This will be an array if you use DOM sourced data, otherwise it will be the array / object / instance that is used to populate the table with data.
  • redraw: boolean
    Reloads the table data after updating a row if true, otherwise does not. Default is true.
Return:
  • Datatable
                        <table id="myTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>#</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Airi Satou</td>
      <td>Accountant</td>
      <td><button data-on-update class="btn btn-primary">Update name</button></td>
    </tr>
    <tr>
      <td>Angelica Ramos</td>
      <td>Chief Executive Officer (CEO)</td>
      <td><button data-on-update class="btn btn-primary">Update name</button></td>
    </tr>
  </tbody>
</table>
                      
                        import {components} from 'metronic-extension';

// Initialize DataTable.
const myTable = new components.Datatable(document.getElementById('myTable'), {
  columnDefs: [
    {targets: 0, data: 'name'},
    {targets: 1, data: 'position'},
    {targets: 2, data: 'actions'},
  ],
});

// Update button click event.
$('#myTable tbody').on('click', '[data-on-update]', evnt => {
  // Display name input dialog.
	const name = window.prompt('Please enter a new name.');
  if (!name)
    // Cancel input or do nothing if input is empty.
    return;

  // Get selection row.
  const row = evnt.currentTarget.closest('tr');

  // Update the name column of row.
  myTable.updateRow(row, {name}, false);
});
                      
public getRowData() Get single row or all rows of data
Parameters:
  • rowSelector: any
    Row selector. See here for more information.
Return:
  • any[]|object Row data.
                        <table id="myTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Airi Satou</td>
      <td>Accountant</td>
    </tr>
    <tr>
      <td>Angelica Ramos</td>
      <td>Chief Executive Officer (CEO)</td>
    </tr>
  </tbody>
</table>
                      
                        import {components} from 'metronic-extension';

// Initialize DataTable.
const myTable = new components.Datatable(document.getElementById('myTable'), {
  columnDefs: [
    {targets: 0, data: 'name'},
    {targets: 1, data: 'position'},
  ],
});

// Retrieve the first row of data.
// The result is "{name: 'Airi Satou', position: 'Accountant'}".
const row = myTable.getRowData(0);

// Get all row data.
// The retrieved result is "[{name: 'Airi Satou', position: 'Accountant'}, {name: 'Angelica Ramos', position: 'Chief Executive Officer (CEO)'}]".
const rows = myTable.getRowData();
                      
public getRowCount() Get the number of rows.
Parameters:
  • rowSelector: any|undefined
    Row selector. See here for more information.
Return:
  • number Number of rows.
                    // Get the number of rows for which the ".select" CSS class is set.
myTable.getRowCount('.selected');

// Get the number of all rows.
myTable.getRowCount();
                  
public getRowNodes() Get row HTML elements.
Return:
  • HTMLTableRowElement[] HTML elements of row.
public getRowObject() Get the DataTable API instance containing the selected rows.
Parameters:
  • rowSelector: any
    Row selector. See here for more information.
Return:
  • DataTables.RowsMethods DataTable API instance containing the selected rows.
public column() Select the column found by a the column selector.
Parameters:
  • columnSelector: any
    Column selector. See here for more information.
  • modifier?: DataTables.ObjectSelectorModifier|undefined
    Specifies the order, paging, and filtering status of the selected columns. Default is none (undefined). See here for more information.
Return:
  • DataTables.ColumnMethods DataTable API instance with selected column in the result set.
public clear() Clear the table of all data.
Return:
  • Datatable
protected ajaxErrorHook() Hook function called when an error occurs in an Ajax request to retrieve table data that can be implemented in a subclass.
This method receives an HTTP status code and an XMLHttpRequest object.
Parameters:
  • httpStatusCode: number
    HTTP status code.
  • xhr: XMLHttpRequest
    XMLHttpRequest object.
                    ajaxErrorHook(httpStatusCode, xhr) {
  if (httpStatusCode === 403)
    // Redirect in case of authentication error (403).
    location.replace('/');
}
                  
Instance Properties
Name Description
public api: DataTables.Api DataTables.Api instance. This is read-only.

Basic

Simple DataTable with no server-side processing.
DataTable has most features enabled by default, so all you need to do to use it with your own tables is to call the construction function.
Name Position Office Age Start date Salary
Tiger Nixon System Architect Edinburgh 61 2011/04/25 320800
Garrett Winters Accountant Tokyo 63 2011/07/25 170750
Ashton Cox Junior Technical Author San Francisco 66 2009/01/12 86000
Cedric Kelly Senior Javascript Developer Edinburgh 22 2012/03/29 433060
              <!--begin::Wrapper-->
<div class="d-flex flex-stack flex-wrap mb-5">
  <!--begin::Search-->
  <div class="d-flex align-items-center position-relative my-1 mb-2 mb-md-0">
    <!--begin::Svg Icon | path: icons/duotune/general/gen021.svg-->
    <span class="svg-icon svg-icon-1 position-absolute ms-4">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2" rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor" />
        <path d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z" fill="currentColor" />
      </svg>
    </span>
    <!--end::Svg Icon-->
    <input data-ref="basicTableKeyword" data-on-search-basic-table type="text" class="form-control form-control-solid w-300px ps-15" placeholder="Search by name" maxlength="70" />
  </div>
  <!--end::Search-->
</div>
<!--end::Wrapper-->
<!--begin::Datatable-->
<table data-ref="basicTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tiger Nixon</td>
      <td>System Architect</td>
      <td>Edinburgh</td>
      <td>61</td>
      <td>2011/04/25</td>
      <td>320800</td>
    </tr>
    <tr>
      <td>Garrett Winters</td>
      <td>Accountant</td>
      <td>Tokyo</td>
      <td>63</td>
      <td>2011/07/25</td>
      <td>170750</td>
    </tr>
    <tr>
      <td>Ashton Cox</td>
      <td>Junior Technical Author</td>
      <td>San Francisco</td>
      <td>66</td>
      <td>2009/01/12</td>
      <td>86000</td>
    </tr>
    <tr>
      <td>Cedric Kelly</td>
      <td>Senior Javascript Developer</td>
      <td>Edinburgh</td>
      <td>22</td>
      <td>2012/03/29</td>
      <td>433060</td>
    </tr>
  </tbody>
</table>
<!--end::Datatable-->
            
              import {components} from 'metronic-extension';

function initBasicTable() {
  return new components.Datatable(ref.basicTable, {
    columnDefs: [
      {targets: 0, data: 'name', name: 'name'},
      {targets: 1, data: 'position', name: 'position'},
      {targets: 2, data: 'office', name: 'office'},
      {targets: 3, data: 'age', name: 'age'},
      {targets: 4, data: 'startDate', name: 'startDate'},
      {targets: 5, data: 'salary', name: 'salary'},
    ],
    pageLength: 3
  });
}

function initBasicTableSearchForm() {
  $('body').on('input', '[data-on-search-basic-table]', () => {
    // Filter data by keyword.
    basicTable.filter('name:name', ref.basicTableKeyword.val());
  });
}

// Search for elements.
const ref = components.selectRef();

// Initialize DataTable.
const basicTable = initBasicTable();

// Initialize events, etc.
initBasicTableSearchForm();
            

Server-side processing

Server-side processing is required to make this demo work. Click here to learn how to build server-side processing.
Name Position Office Age Start date Salary
              <!--begin::Wrapper-->
<div class="d-flex flex-stack flex-wrap mb-5">
  <!--begin::Search-->
  <div class="d-flex align-items-center position-relative my-1 mb-2 mb-md-0">
    <!--begin::Svg Icon | path: icons/duotune/general/gen021.svg-->
    <span class="svg-icon svg-icon-1 position-absolute ms-4">
      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <rect opacity="0.5" x="17.0365" y="15.1223" width="8.15546" height="2" rx="1" transform="rotate(45 17.0365 15.1223)" fill="currentColor" />
        <path d="M11 19C6.55556 19 3 15.4444 3 11C3 6.55556 6.55556 3 11 3C15.4444 3 19 6.55556 19 11C19 15.4444 15.4444 19 11 19ZM11 5C7.53333 5 5 7.53333 5 11C5 14.4667 7.53333 17 11 17C14.4667 17 17 14.4667 17 11C17 7.53333 14.4667 5 11 5Z" fill="currentColor" />
      </svg>
    </span>
    <!--end::Svg Icon-->
    <input data-ref="serverSideProcessingTableKeyword" data-on-search-server-side-processing-table type="text" class="form-control form-control-solid w-300px ps-15" placeholder="Search by name" maxlength="70" />
  </div>
  <!--end::Search-->
</div>
<!--end::Wrapper-->
<!--begin::Datatable-->
<table data-ref="serverSideProcessingTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>
<!--end::Datatable-->
            
              import {components} from 'metronic-extension';

function initServerSideProcessingTable() {
  return new components.Datatable(ref.serverSideProcessingTable, {
    ajax: {
      url: '/api/persons/pages',
      data: d => {
        d.search = {keyword: ref.serverSideProcessingTableKeyword.val()};
      }
    },
    columnDefs: [
      {targets: 0, data: 'name'},
      {targets: 1, data: 'position'},
      {targets: 2, data: 'office'},
      {targets: 3, data: 'age'},
      {targets: 4, data: 'startDate'},
      {targets: 5, data: 'salary'},
    ],
    pageLength: 3
  });
}

function initServerSideProcessingTableSearchForm() {
  $('body').on('input', '[data-on-search-server-side-processing-table]', () => {
    // Reload when the filter is changed.
    // The filter information is set in the parameters sent to the server from the ajax.data optional function.
    serverSideProcessingTable.reload();
  })
}

// Search for elements.
const ref = components.selectRef();

// Initialize DataTable.
const serverSideProcessingTable = initServerSideProcessingTable();

// Initialize events, etc.
initServerSideProcessingTableSearchForm();
            
This table loads data by Ajax. The latest data that has been loaded is shown below. This data will update automatically as any additional data is loaded.
              {
  "data": [
    {
      "id": 5,
      "name": "Airi Satou",
      "position": "Accountant",
      "office": "Tokyo",
      "age": 33,
      "startDate": "2008-11-28",
      "salary": 162700
    },
    {
      "id": 25,
      "name": "Angelica Ramos",
      "position": "Chief Executive Officer (CEO)",
      "office": "London",
      "age": 47,
      "startDate": "2009-10-09",
      "salary": 1200000
    },
    {
      "id": 3,
      "name": "Ashton Cox",
      "position": "Junior Technical Author",
      "office": "San Francisco",
      "age": 66,
      "startDate": "2009-01-12",
      "salary": 86000
    }
  ],
  "recordsTotal": 57,
  "recordsFiltered": 57,
  "draw": "1"
}
            
This is a route script used in server-side processing created with express-sweet, which extends Node.js express.
Server-side processing scripts can be written in any language, using the protocol described in the DataTables documentation.
              const router = require('express').Router();
const {query, validationResult} = require('express-validator');
const PersonModel = require('../../models/PersonModel');

// Get person page data.
router.get('/pages', [
  // Validate parameters.
  query('start').not().isEmpty().isInt({min: 0}),
  query('length').not().isEmpty().isInt({min: 1}),
  query('order').not().isEmpty().isIn(['name', 'position', 'office', 'age', 'startDate', 'salary']),
  query('dir').not().isEmpty().isIn(['asc', 'desc']),
  query('search.keyword').trim().optional({nullable: true, checkFalsy: true}).isLength({max: 70}),
  query('draw').not().isEmpty().isInt({min: 1}),
], async (req, res) => {
  // Check validation results.
  const result = validationResult(req);
  if (!result.isEmpty())
    // If the parameter is invalid, a 400 error is returned.
    return void res.status(400).end();

  // Get page data.
  const paginate = await PersonModel.paginate(req.query);

  // Set the received drawing count as-is in the response.
  paginate.draw = req.query.draw;
  res.json(paginate);
});

module.exports = router;
            
This is a Model script used in server-side processing created with express-sweet, which extends Node.js express.
              const Model = require('express-sweet').database.Model;
const {merge} = require('deep-fusion');

module.exports = class extends Model {
  static get table() {
    return 'person';
  }

  static get attributes() {
    return {
      id: {
        type: this.DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      name: this.DataTypes.STRING,
      position: this.DataTypes.STRING,
      office: this.DataTypes.STRING,
      age: this.DataTypes.INTEGER,
      startDate: this.DataTypes.DATE,
      salary: this.DataTypes.DECIMAL(10, 2),
    };
  }

  /**
   * Get page data.
   */
  static async paginate(options) {
    // Initialize options.
    options = merge({
      start: 0,
      length: 30,
      order: 'name',
      dir: 'asc',
      search: {
        keyword: null,
      },
    }, options);

    // Filter conditions.
    const where = {};
    if (options.search.keyword)
      where.name = {[super.Op.like]: `%${options.search.keyword}%`};

    // Get page data.
    const data = await super.findAll({
      where,
      offset: parseInt(options.start, 10),
      limit: parseInt(options.length, 10),
      order: [super.literal(`${options.order} ${options.dir}`)],
      raw: true,
    });

    // Get the total number of records.
    const recordsTotal = await super.count();

    // Get the number of filtered records.
    const recordsFiltered = await super.count({where});
    return {data, recordsTotal, recordsFiltered};
  }
}
            

Column visibility integration

This example shows how to show/hide table columns using the colvis plugin.
Name Position Office Age Start date Salary
Tiger Nixon System Architect Edinburgh 61 2011/04/25 320800
Garrett Winters Accountant Tokyo 63 2011/07/25 170750
Ashton Cox Junior Technical Author San Francisco 66 2009/01/12 86000
Cedric Kelly Senior Javascript Developer Edinburgh 22 2012/03/29 433060
              <!--begin::Datatable-->
<table data-ref="columnVisibilityTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tiger Nixon</td>
      <td>System Architect</td>
      <td>Edinburgh</td>
      <td>61</td>
      <td>2011/04/25</td>
      <td>320800</td>
    </tr>
    <tr>
      <td>Garrett Winters</td>
      <td>Accountant</td>
      <td>Tokyo</td>
      <td>63</td>
      <td>2011/07/25</td>
      <td>170750</td>
    </tr>
    <tr>
      <td>Ashton Cox</td>
      <td>Junior Technical Author</td>
      <td>San Francisco</td>
      <td>66</td>
      <td>2009/01/12</td>
      <td>86000</td>
    </tr>
    <tr>
      <td>Cedric Kelly</td>
      <td>Senior Javascript Developer</td>
      <td>Edinburgh</td>
      <td>22</td>
      <td>2012/03/29</td>
      <td>433060</td>
    </tr>
  </tbody>
</table>
<!--end::Datatable-->
            
              import {components} from 'metronic-extension';

function initColumnVisibilityTable() {
  return new components.Datatable(ref.columnVisibilityTable, {
    dom: `<'row align-items-center'<'col-auto'B><'col dataTables_pager'p>><'row'<'col-12'tr>><'row'<'col-12 dataTables_pager'p>>`,
    columnDefs: [
      {targets: 0, data: 'name'},
      {targets: 1, data: 'position'},
      {targets: 2, data: 'office'},
      {targets: 3, data: 'age'},
      {targets: 4, data: 'startDate'},
      {targets: 5, data: 'salary'},
    ],
    pageLength: 3,
    buttons: [
      // Button to toggle column visibility.
      {
        extend: 'colvis',
        text: 'Show / hide columns',
        // Columns selector that defines the columns to include in the column visibility button set.
        // CSS selectors, column indexes, etc. can be used to specify columns to switch visibility.
        columns: ':eq(1),:eq(2),:eq(3),:eq(4),:eq(5)',
        // columns: [1,2,3,4,5],
      }
    ],
    // Save the column visibility in the browser.
    stateSave: true,
    /* Enable/Disable saving for various datatables elements. Delete any items you do not wish to save.
        - data.columns.search: This option allows for the saving of the search applied to individual columns to be enabled or disabled.
        - data.columns.visible: This option allows for the saving of the visibility of the columns to be enabled or disabled.
        - data.length: This option allows for the saving of the page length to be enabled or disabled.
        - data.order: This option allows for the saving of the tables column sorting to be enabled or disabled.
        - data.paging: This option allows for the saving of the paging to be enabled or disabled.
        - data.scroller: This option allows for the saving of the scroller position to be enabled or disabled.
        - data.search: This option allows for the saving of the search to be enabled or disabled.
        - data.searchBuilder: This option allows for the saving of the searchBuilder state to be enabled or disabled.
        - data.searchPanes: This option allows for the saving of the searchPanes state to be enabled or-  disabled.
        - data.select: This option allows for the saving of the select state to be enabled or disabled.
    */
    stateSaveParams: (_, data) => {
      delete data.columns.search;
      // delete data.columns.visible;
      delete data.length;
      delete data.order;
      delete data.paging;
      delete data.scroller;
      delete data.search;
      delete data.searchBuilder;
      delete data.searchPanes;
      delete data.select;
    }
  });
}

// Search for elements.
const ref = components.selectRef();

// Initialize DataTable.
const columnVisibilityTable = initColumnVisibilityTable();
            

Column visibility with icon button

This is an example of using icon buttons to show/hide table columns.
Name Position Office Age Start date Salary
Tiger Nixon System Architect Edinburgh 61 2011/04/25 320800
Garrett Winters Accountant Tokyo 63 2011/07/25 170750
Ashton Cox Junior Technical Author San Francisco 66 2009/01/12 86000
Cedric Kelly Senior Javascript Developer Edinburgh 22 2012/03/29 433060
              <!--begin::Datatable-->
<table data-ref="columnVisibilityWithIconButtonTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tiger Nixon</td>
      <td>System Architect</td>
      <td>Edinburgh</td>
      <td>61</td>
      <td>2011/04/25</td>
      <td>320800</td>
    </tr>
    <tr>
      <td>Garrett Winters</td>
      <td>Accountant</td>
      <td>Tokyo</td>
      <td>63</td>
      <td>2011/07/25</td>
      <td>170750</td>
    </tr>
    <tr>
      <td>Ashton Cox</td>
      <td>Junior Technical Author</td>
      <td>San Francisco</td>
      <td>66</td>
      <td>2009/01/12</td>
      <td>86000</td>
    </tr>
    <tr>
      <td>Cedric Kelly</td>
      <td>Senior Javascript Developer</td>
      <td>Edinburgh</td>
      <td>22</td>
      <td>2012/03/29</td>
      <td>433060</td>
    </tr>
  </tbody>
</table>
<!--end::Datatable-->
            
              import {components} from 'metronic-extension';

function initColumnVisibilityWithIconButtonTable() {
  return new components.Datatable(ref.columnVisibilityWithIconButtonTable, {
    dom: `<'row align-items-center'<'col dataTables_pager'p><'col-auto'B>><'row'<'col-12'tr>><'row'<'col-12 dataTables_pager'p>>`,
    columnDefs: [
      {targets: 0, data: 'name'},
      {targets: 1, data: 'position'},
      {targets: 2, data: 'office'},
      {targets: 3, data: 'age'},
      {targets: 4, data: 'startDate'},
      {targets: 5, data: 'salary'},
    ],
    pageLength: 3,
    buttons: {
      dom: {
        button: {
          // Disable the default button class (btn btn-secondary) to set the icon button (btn-icon).
          className: null,
        },
        buttonLiner: {
          // By default, a span element is added within the button, so disable it.
          tag: null,
        }
      },
      buttons: [
        // Button to toggle column visibility.
        {
          extend: 'colvis',
          columns: ':eq(1),:eq(2),:eq(3),:eq(4),:eq(5)',
          text: '<i class="ki-solid ki-gear fs-1"></i>',

          // Icon button style. Switch between them as you wish.
          // className: 'btn btn-sm btn-icon btn-color-primary btn-active-light-primary',
          className: 'btn btn-icon btn-color-gray-500 btn-active-color-primary',

          // Display column drop-downs inside the table container. If this is not set, the column dropdowns will overflow the table container.
          align: 'container',
        }
      ],
    },
    // Save the column visibility in the browser.
    stateSave: true,
    /* Enable/Disable saving for various datatables elements. Delete any items you do not wish to save.
        - data.columns.search: This option allows for the saving of the search applied to individual columns to be enabled or disabled.
        - data.columns.visible: This option allows for the saving of the visibility of the columns to be enabled or disabled.
        - data.length: This option allows for the saving of the page length to be enabled or disabled.
        - data.order: This option allows for the saving of the tables column sorting to be enabled or disabled.
        - data.paging: This option allows for the saving of the paging to be enabled or disabled.
        - data.scroller: This option allows for the saving of the scroller position to be enabled or disabled.
        - data.search: This option allows for the saving of the search to be enabled or disabled.
        - data.searchBuilder: This option allows for the saving of the searchBuilder state to be enabled or disabled.
        - data.searchPanes: This option allows for the saving of the searchPanes state to be enabled or-  disabled.
        - data.select: This option allows for the saving of the select state to be enabled or disabled.
    */
    stateSaveParams: (_, data) => {
      delete data.columns.search;
      // delete data.columns.visible;
      delete data.length;
      delete data.order;
      delete data.paging;
      delete data.scroller;
      delete data.search;
      delete data.searchBuilder;
      delete data.searchPanes;
      delete data.select;
    }
  });
}

// Search for elements.
const ref = components.selectRef();

// Initialize DataTable.
const columnVisibilityWithIconButtonTable = initColumnVisibilityWithIconButtonTable();
            

Disable first ajax call

In this example, the Ajax call for the initial table data retrieval is disabled and Ajax is called to load the data when the button is pressed.
Setting the firstAjax option to false in the DataTable constructor disables the initial Ajax call.
Server-side processing is required to make this demo work. Click here to learn how to build server-side processing.
Name Position Office Age Start date Salary
              <!--begin::Wrapper-->
<div class="d-flex flex-stack flex-wrap mb-5">
  <!--begin::Toolbar-->
  <div class="d-flex justify-content-end">
    <button data-on-load-disable-first-ajax-call-table type="button" class="btn btn-primary">Call Ajax to load data</button>
  </div>
  <!--end::Toolbar-->
</div>
<!--end::Wrapper-->
<!--begin::Datatable-->
<table data-ref="disableFirstAjaxCallTable" class="table table-row-bordered gy-5">
  <thead>
    <tr class="text-start text-gray-700 fw-bold fs-7 gs-0">
      <th>Name</th>
      <th>Position</th>
      <th>Office</th>
      <th>Age</th>
      <th>Start date</th>
      <th>Salary</th>
    </tr>
  </thead>
  <tbody></tbody>
</table>
<!--end::Datatable-->
            
              import {components} from 'metronic-extension';

function initDisableFirstAjaxCallTable() {
  return new components.Datatable(ref.disableFirstAjaxCallTable, {
    firstAjax: false,
    ajax: '/api/persons/pages',
    columnDefs: [
      {targets: 0, data: 'name'},
      {targets: 1, data: 'position'},
      {targets: 2, data: 'office'},
      {targets: 3, data: 'age'},
      {targets: 4, data: 'startDate'},
      {targets: 5, data: 'salary'},
    ],
    pageLength: 3
  });
}

function initDisableFirstAjaxCallTableForm() {
  $('body').on('click', '[data-on-load-disable-first-ajax-call-table]', () => disableFirstAjaxCallTable.reload());
}

// Search for elements.
const ref = components.selectRef();

// Initialize DataTable.
const disableFirstAjaxCallTable = initDisableFirstAjaxCallTable();

// Initialize events, etc.
initDisableFirstAjaxCallTableForm();
            
This is a route script used in server-side processing created with express-sweet, which extends Node.js express.
Server-side processing scripts can be written in any language, using the protocol described in the DataTables documentation.
              const router = require('express').Router();
const {query, validationResult} = require('express-validator');
const PersonModel = require('../../models/PersonModel');

// Get person page data.
router.get('/pages', [
  // Validate parameters.
  query('start').not().isEmpty().isInt({min: 0}),
  query('length').not().isEmpty().isInt({min: 1}),
  query('order').not().isEmpty().isIn(['name', 'position', 'office', 'age', 'startDate', 'salary']),
  query('dir').not().isEmpty().isIn(['asc', 'desc']),
  query('search.keyword').trim().optional({nullable: true, checkFalsy: true}).isLength({max: 70}),
  query('draw').not().isEmpty().isInt({min: 1}),
], async (req, res) => {
  // Check validation results.
  const result = validationResult(req);
  if (!result.isEmpty())
    // If the parameter is invalid, a 400 error is returned.
    return void res.status(400).end();

  // Get page data.
  const paginate = await PersonModel.paginate(req.query);

  // Set the received drawing count as-is in the response.
  paginate.draw = req.query.draw;
  res.json(paginate);
});

module.exports = router;
            
This is a Model script used in server-side processing created with express-sweet, which extends Node.js express.
              const Model = require('express-sweet').database.Model;
const {merge} = require('deep-fusion');

module.exports = class extends Model {
  static get table() {
    return 'person';
  }

  static get attributes() {
    return {
      id: {
        type: this.DataTypes.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      name: this.DataTypes.STRING,
      position: this.DataTypes.STRING,
      office: this.DataTypes.STRING,
      age: this.DataTypes.INTEGER,
      startDate: this.DataTypes.DATE,
      salary: this.DataTypes.DECIMAL(10, 2),
    };
  }

  /**
   * Get page data.
   */
  static async paginate(options) {
    // Initialize options.
    options = merge({
      start: 0,
      length: 30,
      order: 'name',
      dir: 'asc',
      search: {
        keyword: null,
      },
    }, options);

    // Filter conditions.
    const where = {};
    if (options.search.keyword)
      where.name = {[super.Op.like]: `%${options.search.keyword}%`};

    // Get page data.
    const data = await super.findAll({
      where,
      offset: parseInt(options.start, 10),
      limit: parseInt(options.length, 10),
      order: [super.literal(`${options.order} ${options.dir}`)],
      raw: true,
    });

    // Get the total number of records.
    const recordsTotal = await super.count();

    // Get the number of filtered records.
    const recordsFiltered = await super.count({where});
    return {data, recordsTotal, recordsFiltered};
  }
}