jQuery DataTables: Delay search until 3 characters been typed OR a button clicked
JqueryDatatablesJquery Problem Overview
Is there please an option to start the search only after 3 characters have been typed in?
I have written a PHP-script for colleagues displaying 20,000 entries and they complain, that when typing a word, the first few letters cause everything to freeze.
An alternative would be to have the search to be started by a button clicked and not by character typing.
Below is my current code:
$("#my_table").dataTable( {
"bJQueryUI": true,
"sPaginationType": "full_numbers",
"bAutoWidth": false,
"aoColumns": [
/* qdatetime */ { "bSearchable": false },
/* id */ null,
/* name */ null,
/* category */ null,
/* appsversion */ null,
/* osversion */ null,
/* details */ { "bVisible": false },
/* devinfo */ { "bVisible": false, "bSortable": false }
],
"oLanguage": {
"sProcessing": "Wait please...",
"sZeroRecords": "No ids found.",
"sInfo": "Ids from _START_ to _END_ of _TOTAL_ total",
"sInfoEmpty": "Ids from 0 to 0 of 0 total",
"sInfoFiltered": "(filtered from _MAX_ total)",
"sInfoPostFix": "",
"sSearch": "Search:",
"sUrl": "",
"oPaginate": {
"sFirst": "<<",
"sLast": ">>",
"sNext": ">",
"sPrevious": "<"
},
"sLengthMenu": 'Display <select>' +
'<option value="10">10</option>' +
'<option value="20">20</option>' +
'<option value="50">50</option>' +
'<option value="100">100</option>' +
'<option value="-1">all</option>' +
'</select> ids'
}
} );
Jquery Solutions
Solution 1 - Jquery
Solution for version 1.10 -
After looking here for a complete answer and not finding one, I've written this (utilizing code from the documentation, and a few answers here).
The below code works to delay searching until at least 3 characters are entered:
// Call datatables, and return the API to the variable for use in our code
// Binds datatables to all elements with a class of datatable
var dtable = $(".datatable").dataTable().api();
// Grab the datatables input box and alter how it is bound to events
$(".dataTables_filter input")
.unbind() // Unbind previous default bindings
.bind("input", function(e) { // Bind our desired behavior
// If the length is 3 or more characters, or the user pressed ENTER, search
if(this.value.length >= 3 || e.keyCode == 13) {
// Call the API search function
dtable.search(this.value).draw();
}
// Ensure we clear the search if they backspace far enough
if(this.value == "") {
dtable.search("").draw();
}
return;
});
Solution 2 - Jquery
Note: This was for a much earlier version of data tables, please see this answer for jQuery datatables v1.10 and above.
This will modify the behaviour of the input box to only filter when either return has been pressed or there are at least 3 characters in the search:
$(function(){
var myTable=$('#myTable').dataTable();
$('.dataTables_filter input')
.unbind('keypress keyup')
.bind('keypress keyup', function(e){
if ($(this).val().length < 3 && e.keyCode != 13) return;
myTable.fnFilter($(this).val());
});
});
You can see it working here: http://jsbin.com/umuvu4/2. I don't know why the dataTables folks are binding to both keypress and keyup, but I'm overriding both of them to stay compatible although I think keyup is sufficient.
Hope this helps!
Solution 3 - Jquery
Why not try this extended version of Stony's answer :)
var searchWait = 0;
var searchWaitInterval;
$('.dataTables_filter input')
.unbind('keypress keyup')
.bind('keypress keyup', function(e){
var item = $(this);
searchWait = 0;
if(!searchWaitInterval) searchWaitInterval = setInterval(function(){
if(searchWait>=3){
clearInterval(searchWaitInterval);
searchWaitInterval = '';
searchTerm = $(item).val();
oTable.fnFilter(searchTerm);
searchWait = 0;
}
searchWait++;
},200);
});
This will delay the search until the user has stopped typing.
Hope it helps.
Solution 4 - Jquery
Here is how to handle it with the api change in version 1.10
var searchbox = $('#promogrid_filter input');
var pgrid = $('#promogrid').DataTable();
//Remove default datatable logic tied to these events
searchbox.unbind();
searchbox.bind('input', function (e) {
if(this.value.length >= 3) {
pgrid.search(this.value).draw();
}
if(this.value == '') {
pgrid.search('').draw();
}
return;
});
Solution 5 - Jquery
To invoke the server call after the user has typed the mininum characters in the search box, you can follow Allan's suggestion:
> customize the fnSetFilteringDelay() plug-in API function to add > an extra condition on the string length before setting the filter, also > considering a blank string input to clear the filter
So for a minimum of 3 characters, just change line #19 in the plug-in to:
if ((anControl.val().length == 0 || anControl.val().length >= 3) && (sPreviousSearch === null || sPreviousSearch != anControl.val())) {
Solution 6 - Jquery
This works on DataTables 1.10.4:
var table = $('#example').DataTable();
$(".dataTables_filter input")
.unbind()
.bind('keyup change', function(e) {
if (e.keyCode == 13 || this.value == "") {
table
.search(this.value)
.draw();
}
});
Solution 7 - Jquery
My version of datatables 1.10.10
I changed a little things and it works now. So, i'm sharing, cause it was difficulty to make it work for version 1.10.10. Thanks to cale_b, Stony and Sam Barnes. Look at the code to see what i did.
var searchWait = 0;
var searchWaitInterval;
$('.dataTables_filter input')
.unbind() // leave empty here
.bind('input', function(e){ //leave input
var item = $(this);
searchWait = 0;
if(!searchWaitInterval) searchWaitInterval = setInterval(function(){
if(searchWait >= 3){
clearInterval(searchWaitInterval);
searchWaitInterval = '';
searchTerm = $(item).val();
oTable.search(searchTerm).draw(); // change to new api
searchWait = 0;
}
searchWait++;
},200);
});
Solution 8 - Jquery
Here's a plugin-like script that extends datatables.
jQuery.fn.dataTableExt.oApi.fnSetFilteringEnterPress = function ( oSettings ) {
var _that = this;
this.each( function ( i ) {
$.fn.dataTableExt.iApiIndex = i;
var
$this = this,
oTimerId = null,
sPreviousSearch = null,
anControl = $( 'input', _that.fnSettings().aanFeatures.f );
anControl
.unbind( 'keyup' )
.bind( 'keyup', function(e) {
if ( anControl.val().length > 2 && e.keyCode == 13){
_that.fnFilter( anControl.val() );
}
});
return this;
} );
return this;
}
usage:
$('#table').dataTable().fnSetFilteringEnterPress();
Solution 9 - Jquery
for 1.10 version add this code to your javascript in the options. The initComplete overrides the search method and wait to 3 characters are written. Thanks to http://webteamalpha.com/triggering-datatables-to-search-only-on-enter-key-press/ for giving me the light.
var dtable= $('#example').DataTable( {
"deferRender": true,
"processing": true,
"serverSide": true,
"ajax": "get_data.php",
"initComplete": function() {
var $searchInput = $('div.dataTables_filter input');
$searchInput.unbind();
$searchInput.bind('keyup', function(e) {
if(this.value.length > 3) {
dtable.search( this.value ).draw();
}
});
}
} );
} );
Solution 10 - Jquery
Use this
"fnServerData": function (sSource, aoData, fnCallback, oSettings) {
if ($("#myDataTable_filter input").val() !== "" && $("#myDataTable_filter input").val().length < 3)
return;
oSettings.jqXHR = $.ajax({
"dataType": 'json',
"timeout":12000,
"type": "POST",
"url": sSource,
"data": aoData,
"success": fnCallback
});
}
Solution 11 - Jquery
although it does not answer the original question, i had a complex and slow search on my datatables. the filter event was firing after each keypress, which meant a quite noticeable delay after 10 characters. so by introducing a short delay after a keypress before the filter event was fired, where a subsequent keypress reset the counter and prevented the previous search, i was able to make the search seem much faster. others may find this helpful.
i used the answers from stony and christian noel to make this:
var dataTableFilterTimeout;
var dataTableFilterWait = 200; // number of milliseconds to wait before firing filter
$.fn.dataTableExt.oApi.fnSetFilteringEnterPress = function ( oSettings ) {
var _that = this;
this.each( function ( i ) {
$.fn.dataTableExt.iApiIndex = i;
var $this = this;
var oTimerId = null;
var sPreviousSearch = null;
anControl = $( 'input', _that.fnSettings().aanFeatures.f );
anControl.unbind( 'keyup' ).bind( 'keyup', function(e) {
window.clearTimeout(dataTableFilterTimeout);
if ( anControl.val().length > 2 || e.keyCode == 13){
dataTableFilterTimeout = setTimeout(function(){
_that.fnFilter( anControl.val() );
},dataTableFilterWait);
}
});
return this;
} );
return this;
}
Solution 12 - Jquery
You can delay the ajax call to the server by this
var search_thread = null;
$(".dataTables_filter input")
.unbind()
.bind("input", function(e) {
clearTimeout(search_thread);
search_thread = setTimeout(function(){
var dtable = $("#list_table").dataTable().api();
var elem = $(".dataTables_filter input");
return dtable.search($(elem).val()).draw();
}, 300);
});
This code will stop the ajax call if the time between to key press is less then 300 ms, in that way when you write a word, only one ajax call will run and only when you stop typing. You can 'play' with the delay param ( the 300) in order to get more or less delay
Solution 13 - Jquery
You'll probably have to modify the plugin.
And instead of making it X characters, use a delay, so the search starts once they stopped typing for 1 second or so.
So the keydown/keyup binding which is currently triggering the search would be modified with a timer...
var timer;
clearTimeout(timer);
timer = setTimeout(searchFunctionName, 1000 /* timeToWaitInMS */);
Solution 14 - Jquery
You can get the length of the data that is being passed in using data.currentTarget.value.length, please see below.
$('[id$="Search"]').keyup(function (data) {
if (data.currentTarget.value.length > 2 || data.currentTarget.value.length == 0) {
if (timoutOut) { clearTimeout(timoutOut); }
timoutOut = setTimeout(function () {
var value = $('[id$="Search"]').val();
$('#jstree').jstree(true).search(value);
}, 250);
}
});
and obviously you would want this code to run when removing text so set the value to 0
Solution 15 - Jquery
Fixed version for datatables 1.10.12 using API and correctly unbinding the 'input'. Also added search clear on backspace under the character limit.
// Create the Datatable
var pTable = $('#pTable').DataTable();
// Get the Datatable input box and alter events
$('.dataTables_filter input')
.unbind('keypress keyup input')
.bind('keypress keyup input', function (e) {
if ($(this).val().length > 2) {
pTable.search(this.value).draw();
} else if (($(this).val().length == 2) && (e.keyCode == 8)) {
pTable.search('').draw();
}
});
Solution 16 - Jquery
If you're using the old version, it looks like it. Richard's solution works fine. But when I use it, I just added new events, not deleting. Because when code run, table is not yet created. So I found that there is the fnInitComplete method (fire when table created) and I applied it to Ricard's solution. Here it is
$("#my_table").dataTable( {
"bJQueryUI": true,
"sPaginationType": "full_numbers",
"bAutoWidth": false,
...
...,
"fnInitComplete": function (oSettings, json) {
var activeDataTable = $(this).DataTable();
$("#my_table_filter input")
.unbind('keypress keyup')
.bind('keypress keyup', function (e) {
if ($(this).val().length < 3 || e.keyCode !== 13) return;
activeDataTable.fnFilter($(this).val());
});
}
Solution 17 - Jquery
You can use this code on Medtronic datatable or other code to search after using 3 character :
onDataLoad: function (RequestGrid) {
// execute some code on ajax data load
var searchInput = $('div.dataTables_filter input').val();
if (searchInput.length() > 3 || searchInput.length() ==0) {
alert(searchInput);
dt.draw();
}
else {
return false;
}
},
searchInput.length() ==0 for first show.
Solution 18 - Jquery
Can you write your own function to test for the length of the inputed string attached to an onKeyUp event handler and trigger the search function once the min length has been reached?
Something along the lines of:
input.onKeyUp(function() { if(input.length > 3) { mySearchfunction(); } });
...that is, in a pseudo code kind of way but you get the jist.
Solution 19 - Jquery
You can use the parameter by name minlength in order to restrict the search until 3 characters:
function(request, response) {
$.getJSON("/speakers/autocomplete", {
q: $('#keywordSearch').val()
}, response);
}, minLength: 3
Solution 20 - Jquery
This works with DataTables version 1.10.19. It only requires including the js in your website template - useful for a site that has multiple dataTables configured on different pages. Also useful for any slow xhr loading tables, will not allow any new xhr requests until all currently running finish. The search function used is very similar to how the plugin sets up the search function originally.
(function(window, document, $){
var xhring = 0;
$(document).on( 'preXhr.dt', function () {
xhring++;
} );
$(document).on( 'xhr.dt', function () {
xhring--;
} );
//at a minimum wait the full freq, and wait for any pending XHR requests to finish before calling fn
function choke( fn, freq ) {
var
frequency = freq !== undefined ? freq : 200,
last,
timerFn,
timer;
return function () {
var
that = this,
args = arguments;
timerFn = function () {
if (xhring || +new Date() < last + frequency) {
clearTimeout( timer );
timer = setTimeout( timerFn, frequency);
} else {
fn.apply( that, args );
}
}
last = +new Date();
clearTimeout( timer );
timer = setTimeout( timerFn, frequency );
};
}
//See https://github.com/DataTables/DataTables/blob/156faa83386460c578e00c460eca9766e38a0c5f/media/js/jquery.dataTables.js
//See https://github.com/DataTables/Plugins/blob/master/features/searchHighlight/dataTables.searchHighlight.js
$(document).on( 'preInit.dt', function (e, settings, json) {
var previousSearch = settings.oPreviousSearch;
var searchFn = function() {
/* Update all other filter input elements for the new display */
var val = !this.value ? "" : this.value; // mental IE8 fix :-(
/* Now do the filter */
if ( val != previousSearch.sSearch && (val.length >= 3 || val == "")) {
$.fn.dataTable.ext.internal._fnFilterComplete( settings, {
"sSearch": val,
"bRegex": previousSearch.bRegex,
"bSmart": previousSearch.bSmart ,
"bCaseInsensitive": previousSearch.bCaseInsensitive
} );
// Need to redraw, without resorting
settings._iDisplayStart = 0;
$.fn.dataTable.ext.internal._fnDraw( settings );
}
};
var searchDelay = settings.searchDelay !== null ?
settings.searchDelay :
$.fn.dataTable.ext.internal._fnDataSource( settings ) === 'ssp' ?
700 :
200;
var jqFilter = $( 'input', settings.aanFeatures.f )
.off('keyup.DT search.DT input.DT paste.DT cut.DT')
.on('keyup.DT search.DT input.DT paste.DT cut.DT', choke(searchFn, searchDelay))
;
} );
})(window, document, jQuery);
Solution 21 - Jquery
Most of the answers here in some way manipulate the existing DataTable event bindings but personally after spending far too long trying to get this working the best approach I found, in the end, was to just send a dummy value in the search
parameter during the ajax call.
// ... denotes expected code for DataTable to function excluded for clarity.
$("#example").dataTable({
...
'ajax': {
...
'data': function (d) {
d.search.value = d.search.value.length >= 3 ? d.search.value : "##EmptySearch##";
return JSON.stringify(d);
}
}
});
The ##EmptySearch##
string simply acts as a value that shouldn't match any returned data (it's entirely personal preference what to use, but it should be a string that is guaranteed to not match any data). Because the bindings have not been manipulated all the usual bells and whistles still work but nothing meaningful is returned until the search is greater than or equal to three characters. Admittedly it isn't ideal, would prefer to not make the server request at all but this is (in my opinion) the simplest approach that doesn't ruin the existing functionality of the DataTable search.
Solution 22 - Jquery
You need to modify the jquery.datatables.js
----- updated ofcourse you can do a check on lenght > 3, but I think you still need a timer. if you have a lot of data, you don't want to keep getting it filtered after every character update.
Within this method:
jqFilter.keyup( function(e) {
if ( **this.value**.length > 3) {
var n = oSettings.aanFeatures.f;
for ( var i=0, iLen=n.length ; i<iLen ; i++ )
{
if ( n[i] != this.parentNode )
{
$('input', n[i]).val( this.value );
}
}
/* Now do the filter */
_fnFilterComplete( oSettings, {
"sSearch": this.value,
"bRegex": oSettings.oPreviousSearch.bRegex,
"bSmart": oSettings.oPreviousSearch.bSmart
} );
}
} );
Add a timer to the keyup, like shown in one of the answers.
Then go to this site http://jscompress.com/
And past your modified code and the js wil get minified.
Solution 23 - Jquery
Is there a reason you wouldn't just check length on 'change'?
$('.input').change(function() {
if( $('.input').length > 3 ) {
//do the search
}
});