1

I have an HTML select box which will return me the proper value. Task uses select2 and datables My select box

   <select name="filter_model" id="filter_model" class="form-control" required multiple="multiple">
      <option value="Drafted">Drafted</option>
      <option value="Ordered">Ordered</option>
      <option value="Ordered (A)">Ordered (A)</option>
      <option value="PreProduction">PreProduction</option>
      <option value="PreProduction (C)">PreProduction (C)</option>
   </select>

And also I have a jQuery code.

   var table = $('#editable').DataTable();
   var data = $.map( $(this).select2('data'), function( value, key ) {
                if(value.text !== '') {
                   return value.text.trim();
                 }
   });
   var val = data.join('|');
   table.column(5).search(val).draw();

When user selects Drafts, I get proper result. Selecting Order (A) or PreProduction (C), I get result I want. However, when user selects Order or PreProduction, I get two result (Order & Order (A)) and (PreProduction & PreProduction (C)). Someone Please help me.

andrewJames
  • 19,570
  • 8
  • 19
  • 51
Ashish
  • 647
  • 7
  • 18

1 Answers1

2

Finding only exact matches within a specific column of data requires you to use the DataTables search() function with the regex parameter set to true (and you should disable the smart search parameter also):

.search(searchTerm, true, false)

You also need to wrap each Select2 term in a leading ^ and trailing $ which tell the regex that the search term must match from the beginning of the column data all the way through to the end of the column data. It is this step which ensures that Ordered will not also find Ordered (A).

Because parentheses have special meanings in regular expressions (for grouping), and because your select2 values contain parentheses, you have to escape these:

replace('(', '\\(').replace(')', '\\)')

You also need to handle the case where there are no select2 values selected. So that DataTables can reset its filter to "nothing filtered". DataTables expects to receive an empty string for this.

Now you can write the logic to process the select2 multi-selections:

$('#filter_model').on('change.select2', function (e) {
  var data = $.map( $(this).select2('data'), function( value ) {
    return '^' + value.text.replace('(', '\\(').replace(')', '\\)').trim() + '$';
  });
  searchTerm = '';
  if (data.length > 0) {
    searchTerm = data.join('|');
  }
  console.log( searchTerm );
  table.column(5).search(searchTerm, true, false).draw();
});

Here is a runnable demo:

$(document).ready(function() {

  $('#filter_model').select2();

  var table = $('#editable').DataTable();

  $('#filter_model').on('change.select2', function (e) {
    var data = $.map( $(this).select2('data'), function( value ) {
      return '^' + value.text.replace('(', '\\(').replace(')', '\\)').trim() + '$';
    });
    searchTerm = '';
    if (data.length > 0) {
      searchTerm = data.join('|');
    }
    //console.log( searchTerm );
    table.column(5).search(searchTerm, true, false).draw();
  });
  
} );
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
  
    <script src="https://code.jquery.com/jquery-3.6.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">

    <link href="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/css/select2.min.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/npm/select2@4.0.13/dist/js/select2.min.js"></script>

</head>

<body>

<div style="margin: 20px;">

    <select name="filter_model[]" id="filter_model" class="form-control" required multiple="multiple">
        <option value="Drafted">Drafted</option>
        <option value="Ordered">Ordered</option>
        <option value="Ordered (A)">Ordered (A)</option>
        <option value="PreProduction">PreProduction</option>
        <option value="PreProduction (C)">PreProduction (C)</option>
    </select>

    <br><br>

    <table id="editable" class="display dataTable cell-border" style="width:100%">
        <thead>
            <tr>
                <th>Name</th>
                <th>Position</th>
                <th>Office in Country</th>
                <th>Age</th>
                <th>Start date</th>
                <th>Status</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>PreProduction</td>
            </tr>
            <tr>
                <td>Garrett Winters</td>
                <td>Accountant</td>
                <td>Tokyo</td>
                <td>63</td>
                <td>2011/07/25</td>
                <td>PreProduction (C)</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>Ordered</td>
            </tr>
            <tr>
                <td>Cedric Kelly</td>
                <td>Senior Javascript Developer</td>
                <td>Edinburgh</td>
                <td>22</td>
                <td>2012/03/29</td>
                <td>Ordered (A)</td>
            </tr>
            <tr>
                <td>Airi Satou</td>
                <td>Accountant</td>
                <td>Tokyo</td>
                <td>33</td>
                <td>2008/11/28</td>
                <td>Drafted</td>
            </tr>
        </tbody>
    </table>

</div>


</body>

</html>

There's a commented-out logging statement in there. You can un-comment this to see each search term.


Update

Instead of this:

replace('(', '\\(').replace(')', '\\)')

...you may want to consider this Mozilla Guide solution:

replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

where $& means the whole matched string.

It escapes every character which may have a special regex meaning in a string, not just ( and ).

See also the discussions here: Is there a RegExp.escape function in JavaScript?

andrewJames
  • 19,570
  • 8
  • 19
  • 51