17

Using Jquery Datatables with inputs and selects as shown here: http://datatables.net/examples/api/form.html or if I used a custom column render handler to produce the input and selects how can I make the global table search work?

If you view the example you'll notice that only the first column, the read only one, is included in the search, what can I do to include the other columns in the search?

If you view the example in the link in my question and type "Tokyo" into the search all rows are returned. This is because "Tokyo" is an option in all dropdowns. I would want only rows with Tokyo selected to show. If you type in "33" you see no rows even though the first row has a value of "33" in the first column.

I can't seem to find any documentation on how to define what the search value is for a particular cell in a datatable.

5 Answers 5

31

It is not very well documented. And it seems to work differently, or not work at all, between (sub)versions. I think dataTables is intended to automatically detect HTML-columns, but for some reason, most of the times, it doesnt. The safest way is to create your own search-filter :

$.fn.dataTableExt.ofnSearch['html-input'] = function(value) {
    return $(value).val();
};

This will return 33 on <input>'s with value 33, and Tokyo on <select>'s where Tokyo is selected. Then define the desired columns as of type html-input ;

var table = $("#example").DataTable({
    columnDefs: [
       { "type": "html-input", "targets": [1, 2, 3] }
    ] 
});

see demo based on http://datatables.net/examples/api/form.html -> http://jsfiddle.net/a3o3yqkw/


Regarding live data: The issue is, that the type based filter only is called once. dataTables then caches the returned values so it not need to "calculate" all the values over and over. Luckily, dataTables 1.10.x has a built-in function for cells, rows and pages called invalidate that forces dataTables to reset the cache for the selected items.

However, when dealing with <input>'s there is also the problem, that editing the value not is changing the value attribute itself. So even if you call invalidate(), you will still end up in filtering on the old "hardcoded" value.

But I have found a solution for this. Force the <input>'s value attribute to be changed with the <input>'s current value (the new value) and then call invalidate :

$("#example td input").on('change', function() {
  var $td = $(this).closest('td');
  $td.find('input').attr('value', this.value);
  table.cell($td).invalidate();
});

For textareas use text() instead :

$("#example td textarea").on('change', function() {
  var $td = $(this).closest('td');
  $td.find('textarea').text(this.value);
  table.cell($td).invalidate(); 
});

This is also the case when dealing with <select>'s. You will need to update the selected attribute for the relevant <option>'s and then invalidate() the cell as well :

$("#example td select").on('change', function() {
  var $td = $(this).closest('td');
  var value = this.value;
  $td.find('option').each(function(i, o) {
    $(o).removeAttr('selected');
    if ($(o).val() == value) $(o).attr('selected', true);
  })
  table.cell($td).invalidate();
}); 

forked fiddle -> http://jsfiddle.net/s2gbafuz/ Try change content of the inputs and/or the dropdowns, and search for the new values ...

Sign up to request clarification or add additional context in comments.

8 Comments

I like that, seems like a good solution. Only thing I noticed is that if the user changes the value the search still works on the old value not the new one. Any ideas on how to fix that?
@kralco626, yes you were right of course, didnt thought of that, and it was actually an interesting issue. See update. –
@davidkonrad looks like a nice solution but it doesnt seems to work :| i'm playing with your fiddle example and when i change a vallue on one of the inputs or dropdowns it seems to ignore the change when i do the search
@davidkonrad the code in fiddle not works with dropdowns column. It search fine but if you will update the value in cell, search still use old value. I tried to change your code a bit to do this, but no luck for now. Will try more to make it works.
Hey @Pavlo, thank you for feedback. It did not work with <selects> / dropdowns because I only made the code example working for <inputs>. It is pretty straight forward to code the <select> equivalence. Have updated the answer with a new code example and a new (working) fiddle.
|
4

If the point here is to search through all the inputs within a table based on the live values (and "regular" cells), you might want to build your own custom search ($.fn.DataTable.ext.search.push()):

//custom search function
$.fn.DataTable.ext.search.push((_,__,i) => {
  //get current row
  const currentTr = dataTable.row(i).node();
  //look for all <input>, <select> nodes within 
  //that row and check whether current value of
  //any of those contains searched string
  const inputMatch = $(currentTr)
    .find('select,input')
    .toArray()
    .some(input => $(input).val().toLowerCase().includes($('#search').val().toLowerCase()));
  //check whether "regular" cells contain the
  //value being searched
  const textMatch = $(currentTr)
    .children()
    .not('td:has("input,select")')
    .toArray()
    .some(td => $(td).text().toLowerCase().includes($('#search').val().toLowerCase()))
  //make final decision about match
  return inputMatch || textMatch || $('#search').val() == ''
});

The complete DEMO of this approach you may find below:

const srcData = [{id:1,item:'apple',category:'fruit'},{id:2,item:'banana',category:'fruit'},{id:3,item:'goosberry',category:'berry'},{id:4,item:'eggplant',category:'vegie'},{id:5,item:'carrot',category:'vegie'}];

const dataTable = $('table').DataTable({dom:'t',data:srcData,columns:[{title:'Id',data:'id'},{title:'Item',data:'item',render:data=>`<input value="${data}"></input>`},{title:'Category',data:'category',render:data=>`<select>${['fruit', 'vegie', 'berry'].reduce((options, item) => options+='<option value="'+item+'" '+(item == data ? 'selected' : '')+'>'+item+'</option>', '<option value=""></option>')}</select>`}]});

$.fn.DataTable.ext.search.push((_,__,i) => {
  const currentTr = dataTable.row(i).node();
  const inputMatch = $(currentTr)
    .find('select,input')
    .toArray()
    .some(input => $(input).val().toLowerCase().includes( $('#search').val().toLowerCase()));
  const textMatch = $(currentTr)
    .children()
    .not('td:has("input,select")')
    .toArray()
    .some(td => $(td).text().toLowerCase().includes($('#search').val().toLowerCase()))
  return inputMatch || textMatch || $('#search').val() == ''
});

$('#search').on('keyup', () => dataTable.draw());
<!doctype html><html><head><script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script><script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script><link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css"></head><body><input id="search"></input><table></table></body></html>

Comments

1

Replace you input by Textarea, and add the css below. It will make your textarea looks like an input.

textarea{
    height: 30px !important;
    padding: 2px;
    overflow: hidden;
}

1 Comment

You gave me a idea, to just add a hidden textarea in the same cell (next to your input), and it works
0

This should search the entire table instead of specific column(s).

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

$('#input').on('keyup', function() {
  table.search(this.val).draw();
});

2 Comments

I'm trying to use the built in global search. I want it to search only the selected value from the dropdown. If you view the example in the link in my question and type "Tokyo" into the search all rows are returned. This is because "Tokyo" is an option in all dropdowns. I would want only rows with Tokyo selected to show. If you type in "33" you see no rows even though the first row has a value of "33" in the first column.
Okay I get what you're saying now. I did some searching and it doesn't appear to be something that's apart of DataTables. However I did find this. He wrote a snippet that searches for the selected value of a drop down. Sorry I couldn't provide the snippet for you myself!
0

Best thing to do here is just update the cell container to the new value from the input and keep the datatable data object sync with the UI input:

$("#pagesTable td input,#pagesTable td select").on('change', function () {
   var td = $(this).closest("td");
   dataTable.api().cell(td).data(this.value);
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.