javascriptdatatables

DataTables Custom Select Filtering by TR Data Attributes


I'm using DataTables, and added some custom dropdowns for filtering that have values of <tr> data attributes. Everything I've read mentions how to filter by data attributes to <td>. I'm not sure how to implement this as I'm not incredibly familiar with DataTables.

Created a Fiddle: https://jsfiddle.net/pegues/4bw5s0gd/1/

HTML:

<select id="custom-select-filter-1">
    <option value="">Please select filter 1...</option>
    <option value="one">One</option>
    <option value="two">Two</option>
    <option value="three">Three</option>
</select>

<select id="custom-select-filter-2">
    <option value="">Please select filter 2...</option>
    <option value="four">Four</option>
    <option value="five">Five</option>
    <option value="six">Six</option>
</select>

<table id="example">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Category</th>
        </tr>
    </thead>
    <tbody>
        <tr data-testattribute1="one" data-testattribute2="four">
            <td>1</td>
            <td>Apples</td>
            <td>Fruit</td>
        </tr>
        <tr data-testattribute1="two" data-testattribute2="five">
            <td>2</td>
            <td>Oranges</td>
            <td>Fruit</td>
        </tr>
        <tr data-testattribute1="three" data-testattribute2="six">
            <td>3</td>
            <td>Lexus</td>
            <td>Cars</td>
        </tr>
        <tr data-testattribute1="one" data-testattribute2="five">
            <td>4</td>
            <td>Winchester</td>
            <td>Guns</td>
        </tr>
    </tbody>
</table>

JavaScript:

$(document).ready(function(){       
    $('#example').DataTable({
        order: [[1, 'Name']],
    });
    
    $('#custom-select-filter-1').on('change', function(){
        var selectVal = $(this).val();
        
        console.log(selectVal);
    });
    
    $('#custom-select-filter-2').on('change', function(){
        var selectVal = $(this).val();
        
        console.log(selectVal);
    });
});

I've reviewed the DataTables documentation, but do not understand how I could filter based on data attributes for rows, not column cells.

E.g., if one is selected from the first dropdown, then show all rows with the match as in <tr data-testattribute1="one">. If the first dropdown is one and the second dropdown is five, then show all <tr data-testattribute1="one" data-testattribute2="five">, and hide all other rows.

Any help is appreciated.


Solution

  • You can create a custom filter for this using the DataTables search plugin

    $.fn.dataTable.ext.search.push(function (settings, data, dataIndex)
    

    This defines your filter conditions and pushes that function onto an array of filter functions used by DataTables whenever the data is redrawn (triggered by a user action such as paging, sorting, and filtering).

    In your case the logic would be something like the following:

    $.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
        var trNode = settings.aoData[dataIndex].nTr;
        var attr1 = trNode.getAttribute("data-testattribute1");
        var attr2 = trNode.getAttribute("data-testattribute2");
        
        var val1 = $('#custom-select-filter-1').val();
        var val2 = $('#custom-select-filter-2').val();
             
        if ( (val1 === "" || val1 === attr1) 
            && (val2 === "" || val2 === attr2) ) {
            return true;
        }
        return false;
    });
    

    You can access the <tr> node for the DataTable data row via the table's settings object: settings.aoData[dataIndex].nTr.

    From there, it's a matter of getting the attributes and comparing them to the user inputs. An empty string (empty input) means "no filter".


    Here is a runnable demo:

    $.fn.dataTable.ext.search.push(function (settings, data, dataIndex) {
      var trNode = settings.aoData[dataIndex].nTr;
        var attr1 = trNode.getAttribute("data-testattribute1");
        var attr2 = trNode.getAttribute("data-testattribute2");
        
        var val1 = $('#custom-select-filter-1').val();
        var val2 = $('#custom-select-filter-2').val();
         
      if ( (val1 === "" || val1 === attr1) 
          && (val2 === "" || val2 === attr2) ) {
          return true;
      }
      return false;
    });
    
    $(document).ready(function(){
    
        var table = $('#example').DataTable({
            order: [[1, 'Name']],
        });
        
        $('#custom-select-filter-1').on('change', function(){
            table.draw();
        });
        
        $('#custom-select-filter-2').on('change', function(){
            table.draw();
        });
    });
    <!doctype html>
    <html>
    <head>
      <meta charset="UTF-8">
      <title>Demo</title>
      <script src="https://code.jquery.com/jquery-3.5.0.js"></script>
      <script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.js"></script>
      <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.12.1/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;">
    
    <select id="custom-select-filter-1">
        <option value="">Please select filter 1...</option>
        <option value="one">One</option>
        <option value="two">Two</option>
        <option value="three">Three</option>
    </select>
    
    <select id="custom-select-filter-2">
        <option value="">Please select filter 2...</option>
        <option value="four">Four</option>
        <option value="five">Five</option>
        <option value="six">Six</option>
    </select>
    
    <table id="example">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Category</th>
            </tr>
        </thead>
        <tbody>
            <tr data-testattribute1="one" data-testattribute2="four">
                <td>1</td>
                <td>Apples</td>
                <td>Fruit</td>
            </tr>
            <tr data-testattribute1="two" data-testattribute2="five">
                <td>2</td>
                <td>Oranges</td>
                <td>Fruit</td>
            </tr>
            <tr data-testattribute1="three" data-testattribute2="six">
                <td>3</td>
                <td>Lexus</td>
                <td>Cars</td>
            </tr>
            <tr data-testattribute1="one" data-testattribute2="five">
                <td>4</td>
                <td>Winchester</td>
                <td>Guns</td>
            </tr>
        </tbody>
    </table>
    
    </div>
    
    
    
    </body>
    </html>

    Note the use of table.draw(); to trigger the re-draw; and note that the table variable has been added to the code which creates the DataTable, to support the draw() call:

    var table = $('#example').DataTable({ ...