Search code examples
javascripthtmljquerydatatables

How to create column search in datatables if the table is initialized using data of javascript's array of array?


I'm new to writing code and I'm having trouble to initialize table using datatables. What I'm trying to achieve is to create table where user can search/filter each of the table's column.

I know how to simply initialize datatables like:

const dataSet = [['a','b','x'],['c','d','y'],['e','f','z']];
const headers = [{'title':'A'},{'title': 'B'},{'title': 'C'}]

$(document).ready(function () {
    $('#example').DataTable({
        data: dataSet,
        columns: headers,
    });
});

but I really have no idea where to put dataSet and headers in this example:

$(document).ready(function () {
    // Setup - add a text input to each footer cell
    $('#example thead tr')
        .clone(true)
        .addClass('filters')
        .appendTo('#example thead');
 
    var table = $('#example').DataTable({
        orderCellsTop: true,
        fixedHeader: true,
        initComplete: function () {
            var api = this.api();
 
            // For each column
            api
                .columns()
                .eq(0)
                .each(function (colIdx) {
                    // Set the header cell to contain the input element
                    var cell = $('.filters th').eq(
                        $(api.column(colIdx).header()).index()
                    );
                    var title = $(cell).text();
                    $(cell).html('<input type="text" placeholder="' + title + '" />');
 
                    // On every keypress in this input
                    $(
                        'input',
                        $('.filters th').eq($(api.column(colIdx).header()).index())
                    )
                        .off('keyup change')
                        .on('change', function (e) {
                            // Get the search value
                            $(this).attr('title', $(this).val());
                            var regexr = '({search})'; //$(this).parents('th').find('select').val();
 
                            var cursorPosition = this.selectionStart;
                            // Search the column for that value
                            api
                                .column(colIdx)
                                .search(
                                    this.value != ''
                                        ? regexr.replace('{search}', '(((' + this.value + ')))')
                                        : '',
                                    this.value != '',
                                    this.value == ''
                                )
                                .draw();
                        })
                        .on('keyup', function (e) {
                            e.stopPropagation();
 
                            $(this).trigger('change');
                            $(this)
                                .focus()[0]
                                .setSelectionRange(cursorPosition, cursorPosition);
                        });
                });
        },
    });
});

Create table where user can search/filter each of the table's column using datatables (link)


Solution

  • To start with, the basic example in your question does not work:

    const dataSet = [['a','b'],['c','d'],['e','f']];
    const headers = [{'title':'A'},{'title': 'B'},{'title': 'C'}}
    
    $(document).ready(function () {
        $('#example').DataTable({
            data: dataSet,
            columns: headers,
        });
    });
    

    You need to fix that first:

    1. In const headers, the data needs to end with }] not }}. I assume that is just a typo.

    2. The headers array defines three column headings. But each row of data in dataSet only defines two columns of data. So, you have to make these two data sets compatible - for example, by adding a third column of data or by removing the third column heading. Here is the data with a third column of data:

    const dataSet = [['a','b','x'],['c','d','y'],['e','f','z']];
    

    Now you can add the above (corrected) code to your more complex example - and also add the same two options to your DataTable:

    data: dataSet,
    columns: headers,
    

    If your HTML table does not have any headings defined, then you have one extra step you need to take.

    I will assume you have something like this:

    <table id="example" class="display dataTable cell-border" style="width:100%">
    </table>
    

    Note that the <table> tag does not have any <thead> content.

    You therefore have to create the <thead> HTML and add it to the above table. This is because the rest of the code (which builds the column filters) assumes this header row already exists. You can see this in the official example.

    Here is one way to build the missing <thead> row, and add it to the <table>:

    // add a header row to your table 
    var th = '<thead><tr>';
    headers.forEach(header => th = th + '<th>' + header.title + '</th>');
    th = th + '</tr></thead>';
    $( th ).appendTo( '#example' );
    

    Now that the header row has been added to the table, the rest of the code works without any additional changes.

    The full code is shown below in this runnable demo:

    $(document).ready(function() {
    
    
      const dataSet = [
        ['a', 'b', 'x'],
        ['c', 'd', 'y'],
        ['e', 'f', 'z']
      ];
      const headers = [{
        'title': 'A'
      }, {
        'title': 'B'
      }, {
        'title': 'C'
      }];
    
      // add a header row to your table 
      var th = '<thead><tr>';
      headers.forEach(header => th = th + '<th>' + header.title + '</th>');
      th = th + '</tr></thead>';
      $(th).appendTo('#example');
    
      // Setup - add a text input to each footer cell
      $('#example thead tr')
        .clone(true)
        .addClass('filters')
        .appendTo('#example thead');
    
      var table = $('#example').DataTable({
    
        data: dataSet,
        columns: headers,
    
        orderCellsTop: true,
        fixedHeader: true,
        initComplete: function() {
          var api = this.api();
          //console.log( api.columns().eq(0) );
          // For each column
          api
            .columns()
            .eq(0)
            .each(function(colIdx) {
              //console.log( $(api.column(colIdx).header()).index() );
              // Set the header cell to contain the input element
              var cell = $('.filters th').eq(
                $(api.column(colIdx).header()).index()
              );
              //console.log( headers[colIdx].title );
              var title = $(cell).text();
              $(cell).html('<input type="text" placeholder="' + title + '" />');
    
              // On every keypress in this input
              $(
                  'input',
                  $('.filters th').eq($(api.column(colIdx).header()).index())
                )
                .off('keyup change')
                .on('change', function(e) {
                  // Get the search value
                  $(this).attr('title', $(this).val());
                  var regexr = '({search})'; //$(this).parents('th').find('select').val();
    
                  var cursorPosition = this.selectionStart;
                  // Search the column for that value
                  api
                    .column(colIdx)
                    .search(
                      this.value != '' ?
                      regexr.replace('{search}', '(((' + this.value + ')))') :
                      '',
                      this.value != '',
                      this.value == ''
                    )
                    .draw();
                })
                .on('keyup', function(e) {
                  e.stopPropagation();
    
                  $(this).trigger('change');
                  //$(this)
                  //  .focus()[0]
                  //  .setSelectionRange(cursorPosition, cursorPosition);
                });
            });
        },
      });
    });
    <!doctype html>
    <html>
    
    <head>
      <meta charset="UTF-8">
      <title>Demo</title>
      <script src="https://code.jquery.com/jquery-3.5.1.js"></script>
      <script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
      <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
      <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
    
    </head>
    
    <body>
    
      <div style="margin: 20px;">
    
        <table id="example" class="display dataTable cell-border" style="width:100%">
        </table>
    
      </div>
    
    
    
    </body>
    
    </html>