jQuery DataTables: Retrasar la búsqueda hasta que se hayan escrito 3 caracteres O se haya hecho clic en un botón

82

¿Existe una opción para iniciar la búsqueda solo después de que se hayan escrito 3 caracteres?

He escrito un script PHP para colegas que muestra 20.000 entradas y se quejan de que al escribir una palabra, las primeras letras hacen que todo se congele.

Una alternativa sería que la búsqueda se inicie haciendo clic en un botón y no escribiendo un carácter.

A continuación se muestra mi código actual:

$("#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'
        }
} );
Alexander Farber
fuente

Respuestas:

75

Solución para la versión 1.10 -

Después de buscar aquí una respuesta completa y no encontrar una, escribí esto (utilizando el código de la documentación y algunas respuestas aquí).

El siguiente código funciona para retrasar la búsqueda hasta que se ingresen al menos 3 caracteres:

// 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;
    });
nombre_usuario_aleatorio
fuente
3
Para aquellos de ustedes que tengan problemas para hacer que esto funcione, intente usar esto en el init.dtevento, por ejemplo $('#yourTable').on('init.dt', function () { ... });.
arao6
En la versión 11, primero debe establecer la cadena de búsqueda y luego ejecutar fnDraw () de la siguiente manera: $ (". Datatable"). DataTable (). Api (). Search ("aaaa2"); $ (". datatable "). dataTable (). fnDraw ()
Hesham Yassin
2
Tuve entrada en lugar de función de teclado, ahora está funcionando bien. Gracias
azza idz
1
@Maxime Lo devolví a la edición que funcionó y no hizo esas discrepancias de nombres de variables erróneas. Avíseme si cree que aún necesita modificaciones o atención.
random_user_name
1
@cale_b Puedo confirmar que esto todavía funciona para 1.10.16. Gracias.
AnotherDeveloper
77

Nota: Esto fue para una versión mucho anterior de las tablas de datos, consulte esta respuesta para las tablas de datos jQuery v1.10 y posteriores.


Esto modificará el comportamiento del cuadro de entrada para filtrar solo cuando se haya presionado return o cuando haya al menos 3 caracteres en la búsqueda:

$(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());
    });
});

Puedes verlo funcionando aquí: http://jsbin.com/umuvu4/2 . No sé por qué la gente de las tablas de datos se vincula tanto a la pulsación de teclas como a la activación de teclas, pero estoy anulando ambas para que sigan siendo compatibles, aunque creo que la activación de teclas es suficiente.

¡Espero que esto ayude!

Ricardo
fuente
2
También noté esto. La vinculación tanto a la pulsación de tecla como a la activación de teclas significa que la consulta se activa dos veces. Para aquellos que miran en casa, simplemente deben eliminar uno u otro tanto del desvío como del vínculo.
Thunder Rabbit
1
esta solución no funciona al presionar la tecla de retroceso. @Sam Barnes es la mejor respuesta
Idrees Khan
2
Como alternativa a la excelente respuesta de Sam Barnes, puede modificar esto para tener en cuenta el retroceso (y limpiar el campo) reemplazando e.keycode != 13con e.keyCode > 13, que también se activará cuando salgan del campo.
cincodenada
2
Desafortunadamente, esto no funciona con la versión 1.10
random_user_name
Siguiendo lo que dijo @ThunderRabbit, la mejor manera que encontré fue desvincular ambos, pero solo volver a vincular uno u otro. .unbind('keypress keyup') .bind('keypress', function(e) ...
nageeb
33

¿Por qué no probar esta versión extendida de la respuesta de Stony :)

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);

});

Esto retrasará la búsqueda hasta que el usuario deje de escribir.

Espero eso ayude.

Sam Barnes
fuente
funciona bien. pero tengo que cambiar oTable.fnFilter (...) para hacer referencia a mi instancia de tabla de datos.
YudhiWidyatama
Esta no es realmente una versión extendida, es una solución totalmente diferente (pero útil). Sin embargo, estoy confundido en cuanto a lo que hace el parámetro searchWait que no se pudo lograr setTimeout(function(){...}, 600), ya que la función no parece volver a activarse en más caracteres.
cincodenada
@cincodenada tiene que ser a setInterval, porque se reinicia cada 200 / 600ms y verifica si searchWait no se restableció a 0. Por ejemplo, si continúa ingresando algo en la entrada, siempre restablecerá searchWait a 0 = la búsqueda nunca se ejecuta. Sin embargo, encuentro el uso de searchWait como número entero, que cuenta hasta 3, bastante oscuro. Mejor sería solo una bandera de verdadero / falso si la entrada del usuario sucediera y una setIntervalde 600.
r3mark
3
Desde jqueryDatatables 1.10.3, hay una opción para esto: searchDelay
panmari
1
@panmari - searchDelay solo retrasará la búsqueda durante el tiempo especificado y (activará ajax) volverá a dibujar la tabla después, no cuando el usuario dejó de escribir, lo que la mayoría de nosotros esperaba.
Chris Landeza
11

A continuación se explica cómo manejarlo con el cambio de api en la versión 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;
});
Chad Kuehn
fuente
8

Mi versión de tablas de datos 1.10.10

Cambié algunas cosas y ahora funciona. Entonces, lo estoy compartiendo, porque fue difícil hacerlo funcionar para la versión 1.10.10. Gracias a cale_b, Stony y Sam Barnes. Mira el código para ver lo que hice.

    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);

    });
Zante
fuente
7

Aquí hay un script similar a un complemento que amplía las tablas de datos.

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;
}

uso:

$('#table').dataTable().fnSetFilteringEnterPress();
Christian Noel
fuente
¿No quieres "si la longitud es superior a 2 o la tecla enter presionada?if ( anControl.val().length > 2 || e.keyCode == 13)
Jeromy French
sí, eso también funciona. Estoy más centrado en el lado de la validación, de modo que incluso si se pasa una cadena vacía y se presiona la tecla Intro, no sucede nada.
Christian Noel
6

Para hacer es invocar la llamada al servidor después de que el usuario haya escrito los caracteres mínimos en el cuadro de búsqueda, puede seguir la sugerencia de Allan :

Personalice la función API del complemento fnSetFilteringDelay () para agregar una condición adicional en la longitud de la cadena antes de configurar el filtro, considerando también una entrada de cadena en blanco para borrar el filtro

Entonces, para un mínimo de 3 caracteres, simplemente cambie la línea # 19 en el complemento a:

if ((anControl.val().length == 0 || anControl.val().length >= 3) && (sPreviousSearch === null || sPreviousSearch != anControl.val())) {
Marius Butuc
fuente
5

Esto funciona en 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();
        }
    });

JSFiddle

Márcio Souza Júnior
fuente
4

para la versión 1.10 agregue este código a su javascript en las opciones. InitComplete anula el método de búsqueda y espera a que se escriban 3 caracteres. Gracias a http://webteamalpha.com/triggering-datatables-to-search-only-on-enter-key-press/ por darme la luz.

    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();
                }
            });
        }

    } );
} );
mato gallardo
fuente
3

Utilizar esta

   "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
            });
        }
Nitin Bourai
fuente
+1 Niza. Esto se integra muy bien en la definición de tablas de datos. por cierto, en mi caso, fue suficiente no devolver todo el obj aoData, sino solo aoData [5] ['valor'] ['valor'] (el texto escrito en el campo de entrada).
Werner
3

aunque no responde a la pregunta original, tuve una búsqueda compleja y lenta en mis tablas de datos. el evento de filtro se activaba después de cada pulsación de tecla, lo que significaba un retraso bastante notable después de 10 caracteres. así que al introducir un breve retraso después de una pulsación de tecla antes de que se disparara el evento de filtro, donde una pulsación de tecla posterior restablecía el contador e impedía la búsqueda anterior, pude hacer que la búsqueda pareciera mucho más rápida. otros pueden encontrar esto útil.

Usé las respuestas de Stony y Christian Noel para hacer esto:

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;
}
pgee70
fuente
3

Puede retrasar la llamada ajax al servidor por esto

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);
        });

Este código detendrá la llamada ajax si el tiempo entre la pulsación de la tecla es inferior a 300 ms, de esa manera, cuando escribe una palabra, solo se ejecutará una llamada ajax y solo cuando deje de escribir. Puede 'jugar' con el parámetro de retardo (el 300) para obtener más o menos retardo

zion ben yacov
fuente
2

Probablemente tendrá que modificar el complemento.

Y en lugar de convertirlos en X caracteres, use un retraso, para que la búsqueda comience una vez que dejen de escribir durante aproximadamente 1 segundo.

Por lo tanto, el enlace de teclado / teclado que actualmente está activando la búsqueda se modificaría con un temporizador ...

var timer;
clearTimeout(timer);
timer = setTimeout(searchFunctionName, 1000 /* timeToWaitInMS */);
smdrager
fuente
1
Por "modificar el complemento", ¿te refieres a editar jquery.dataTables.js? ¿Y sabes cómo "minimizarlo" después?
Alexander Farber
2

Versión fija para tablas de datos 1.10.12 usando API y desvinculando correctamente la 'entrada'. También se agregó la búsqueda clara en el retroceso por debajo del límite de caracteres.

    // 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();
        }
    });
Tino
fuente
2

Si está usando la versión anterior, lo parece. La solución de Richard funciona bien. Pero cuando lo uso, solo agregué nuevos eventos, no eliminé. Porque cuando se ejecuta el código, la tabla aún no se crea. Entonces encontré que existe el método fnInitComplete (disparar cuando se crea la tabla) y lo apliqué a la solución de Ricard. Aquí está

$("#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());
                    });
                }
cihancoskun
fuente
2

Puede usar este código en la tabla de datos de Medtronic u otro código para buscar después de usar 3 caracteres:

        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 para el primer show.

LPLN
fuente
1

¿Puede escribir su propia función para probar la longitud de la cadena ingresada adjunta a un controlador de eventos onKeyUp y activar la función de búsqueda una vez que se haya alcanzado la longitud mínima?

Algo parecido a:

input.onKeyUp (function () {
    if (input.length> 3) {
        mySearchfunction ();
    }
});

... es decir, en una especie de pseudocódigo pero obtienes la clave.

Chris
fuente
1

Puede utilizar el parámetro por nombre minlength para restringir la búsqueda hasta 3 caracteres:

function(request, response) {
    $.getJSON("/speakers/autocomplete", {  
        q: $('#keywordSearch').val()
    }, response);
}, minLength: 3
Lokesh S
fuente
1

Puede obtener la longitud de los datos que se pasan utilizando data.currentTarget.value.length, consulte a continuación.

$('[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);
            }
        });

y obviamente querrá que este código se ejecute al eliminar texto, así que configure el valor en 0

Tom McDonough
fuente
0

Esto funciona con DataTables versión 1.10.19. Solo requiere incluir js en la plantilla de su sitio web, útil para un sitio que tiene múltiples tablas de datos configuradas en diferentes páginas. También es útil para cualquier tabla de carga lenta de xhr, no permitirá nuevas solicitudes de xhr hasta que finalicen todas las que se están ejecutando actualmente. La función de búsqueda utilizada es muy similar a cómo el complemento configura la función de búsqueda originalmente.

(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);
sitio
fuente
-1

¿Hay alguna razón por la que no solo verifique la longitud en el 'cambio'?

$('.input').change(function() {
  if( $('.input').length > 3 ) {
     //do the search
  }
});
jimyshock
fuente
2
Porque DataTables ya está vinculado a esto, y llama automáticamente a la búsqueda. Tienes que interceptar / alterar los enlaces.
random_user_name
-1

Necesita modificar jquery.datatables.js

----- actualizado, por supuesto, puede verificar la longitud> 3, pero creo que aún necesita un temporizador. si tienes muchos datos, no querrás que se sigan filtrando después de cada actualización de personajes.

Dentro de este método:

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 
                } );
         }
        } );

Agregue un temporizador al teclado, como se muestra en una de las respuestas.

Luego vaya a este sitio http://jscompress.com/

Y más allá de su código modificado y el js se minificará.

Tahir Malik
fuente
Hola, gracias, pero ¿podría agregar $ ('. Input'). Length> 3 o $ (# input '). Length> 3 check en lugar de un temporizador? Sin embargo, no estoy seguro de cómo hacer referencia al campo de búsqueda.
Alexander Farber
por supuesto, puede verificar la longitud> 3, pero creo que aún necesita un temporizador. Si tienes muchos datos, no querrás seguir filtrando después de cada actualización de personaje. Actualicé la respuesta con la verificación correcta en la longitud por encima de los 3 caracteres. Agregar el temporizador es el siguiente paso valioso.
Tahir Malik