【问题标题】:jQuery DataTables: Delay search until 3 characters been typed OR a button clickedjQuery DataTables:延迟搜索,直到输入 3 个字符或单击按钮
【发布时间】:2011-07-29 18:22:42
【问题描述】:

是否可以选择仅在输入 3 个字符后才开始搜索?

我为显示 20,000 个条目的同事编写了一个 PHP 脚本,他们抱怨说,在输入一个单词时,前几个字母会导致所有内容都冻结。

另一种方法是通过单击按钮而不是键入字符来开始搜索。

以下是我当前的代码:

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

【问题讨论】:

  • 对于延迟只在 dataTable config { searchDelay: value } 中尝试这个值是毫秒的整数

标签: jquery datatables


【解决方案1】:

1.10 版解决方案 -

在此处寻找完整答案但没有找到之后,我写了这个(利用文档中的代码,以及这里的一些答案)。

以下代码用于延迟搜索,直到输入至少 3 个字符:

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

【讨论】:

  • 对于那些无法让它工作的人,请尝试在 init.dt 事件中使用它,例如$('#yourTable').on('init.dt', function () { ... });.
  • 我有输入而不是 keydown 功能,它现在运行良好。谢谢
  • @Maxime 我已经将它回滚到有效的编辑并且没有使那些错误的变量名不匹配。如果您认为它仍需要编辑/关注,请告诉我。
  • @cale_b 我​​可以确认这仍然适用于 1.10.16。谢谢。
  • 2020年有没有更好的解决方案? :)
【解决方案2】:

注意:这是针对更早版本的数据表,有关 jQuery 数据表 v1.10 及更高版本,请参阅 this answer


这将修改输入框的行为,使其仅在按下回车键或搜索中至少有 3 个字符时进行过滤:

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

您可以在此处看到它的工作原理:http://jsbin.com/umuvu4/2。我不知道为什么 dataTables 的人同时绑定到 keypress 和 keyup,但尽管我认为 keyup 就足够了,但我还是覆盖了它们以保持兼容。

希望这会有所帮助!

【讨论】:

  • 也注意到了这一点。绑定到 keypress 和 keyup 意味着查询被触发两次。对于那些在家看的人,你应该从解绑和绑定中取出一个或另一个。
  • 这个解决方案在按下退格键时不起作用。 @Sam Barnes 是最好的答案
  • 作为 Sam Barnes 出色答案的替代方案,您可以通过将 e.keycode != 13 替换为 e.keyCode &gt; 13 来修改它以考虑退格(并清除字段),当他们标记出来时也会触发领域。
  • 不幸的是,这对于 1.10 版不起作用
  • 按照@ThunderRabbit 所说,我发现最好的方法是解除两者的绑定,但只能重新绑定其中一个。 .unbind('keypress keyup') .bind('keypress', function(e) ...
【解决方案3】:

为什么不试试这个 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);

});

这将延迟搜索,直到用户停止输入。

希望对你有帮助。

【讨论】:

  • 效果很好。但我必须更改 oTable.fnFilter(...) 以引用我的数据表实例。
  • 这并不是一个真正的扩展版本,它是一个完全不同(但有用)的解决方案。不过,我对 setTimeout(function(){...}, 600) 无法完成的 searchWait 参数的作用感到困惑,因为该函数似乎不会在更多字符上重新触发。
  • @cincodenada 它必须是 setInterval,因为它每 200/600 毫秒重新触发一次并检查 searchWait 是否未重置为 0。例如如果您继续在输入中输入内容,您将始终将 searchWait 重置为 0 = 永远不会执行搜索。但是,我发现使用 searchWait 作为整数,它计数为 3,相当模糊。如果用户输入发生并且setInterval 为 600,则最好只是一个真/假标志。
  • 从 jqueryDatatables 1.10.3 开始,有一个选项:searchDelay
  • @panmari - searchDelay 只会延迟搜索指定的时间,然后会(触发 ajax)重绘表格,而不是当用户停止输入时,我们大多数人都期待。
【解决方案4】:

这里是1.10版本的api变化处理方法

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

【讨论】:

    【解决方案5】:

    我的数据表版本 1.10.10

    我改变了一些东西,它现在可以工作了。所以,我正在分享,因为很难让它适用于 1.10.10 版本。感谢 cal_b、Stony 和 Sam Barnes。查看代码,看看我做了什么。

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

    【讨论】:

      【解决方案6】:

      这适用于 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

      【讨论】:

        【解决方案7】:

        要在用户在搜索框中输入最小字符后调用服务器调用,您可以关注Allan's suggestion

        自定义fnSetFilteringDelay() plug-in API function添加 在设置过滤器之前对字符串长度的额外条件,也 考虑一个空白字符串输入来清除过滤器

        所以对于至少 3 个字符,只需将 the plug-in 中的第 19 行更改为:

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

        【讨论】:

        • 这是最新 1.11.x 的正确解决方案。它将搜索延迟技巧与触发搜索所需的最小字符相结合。所有其他解决方案仅部分起作用。非常感谢!!
        【解决方案8】:

        这是一个扩展数据表的类似插件的脚本。

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

        用法:

        $('#table').dataTable().fnSetFilteringEnterPress();
        

        【讨论】:

        • 你不想“如果长度大于 2 按下输入键吗?if ( anControl.val().length &gt; 2 || e.keyCode == 13)
        • 是的,这也有效。我只是更专注于验证方面,因此即使传递了一个空字符串并且按下了回车键,也不会发生任何事情。
        【解决方案9】:

        对于 1.10 版本,将此代码添加到您的 javascript 选项中。 initComplete 覆盖搜索方法并等待写入 3 个字符。 感谢http://webteamalpha.com/triggering-datatables-to-search-only-on-enter-key-press/给了我光明。

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

        【讨论】:

          【解决方案10】:

          使用这个

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

          【讨论】:

          • +1 不错。这很好地集成在数据表定义中。顺便说一句,在我的情况下,不返回整个 aoData obj 就足够了,而只返回 aoData[5]['value']['value'] (在输入字段中键入的文本)。
          【解决方案11】:

          虽然它没有回答原始问题,但我对数据表的搜索复杂而缓慢。每次按键后都会触发过滤器事件,这意味着在 10 个字符后会有相当明显的延迟。因此,通过在触发过滤器事件之前在按键之后引入短暂的延迟,随后的按键重置计数器并阻止先前的搜索,我能够使搜索看起来更快。其他人可能会觉得这很有帮助。

          我使用了 stony 和 christian noel 的答案来制作这个:

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

          【讨论】:

            【解决方案12】:

            你可以通过这个来延迟对服务器的ajax调用

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

            如果按键之间的时间少于 300 毫秒,此代码将停止 ajax 调用,这样当你写一个单词时,只有一个 ajax 调用会运行,并且只有在你停止输入时才会运行。 您可以“玩”延迟参数(300)以获得或多或少的延迟

            【讨论】:

              【解决方案13】:

              您可能需要修改插件。

              并且不要将其设为 X 个字符,而是使用延迟,因此一旦他们停止输入 1 秒左右,搜索就会开始。

              因此,当前触发搜索的 keydown/keyup 绑定将使用计时器进行修改...

              var timer;
              clearTimeout(timer);
              timer = setTimeout(searchFunctionName, 1000 /* timeToWaitInMS */);
              

              【讨论】:

              • “修改插件”是指编辑jquery.dataTables.js吗?你知道之后如何“最小化”它吗?
              【解决方案14】:

              你可以通过data.currentTarget.value.length获取正在传入的数据的长度,请看下文。

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

              显然您希望在删除文本时运行此代码,因此将值设置为 0

              【讨论】:

                【解决方案15】:

                使用 API 并正确取消绑定“输入”的数据表 1.10.12 的固定版本。还添加了字符限制下的退格搜索清除。

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

                【讨论】:

                  【解决方案16】:

                  如果您使用的是旧版本,它看起来像它。理查德的解决方案效果很好。 但是当我使用它时,我只是添加了新事件,而不是删除。因为当代码运行时,表还没有创建。 所以我发现有 fnInitComplete 方法(创建表时触发)并将其应用于 Ricard 的解决方案。 在这里

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

                  【讨论】:

                    【解决方案17】:

                    您可以在 Medtronic 数据表上使用此代码或其他代码在使用 3 个字符后进行搜索:

                            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 首次显示。

                    【讨论】:

                      【解决方案18】:

                      您能否编写自己的函数来测试附加到 onKeyUp 事件处理程序的输入字符串的长度,并在达到最小长度后触发搜索函数?

                      类似的东西:

                      输入.onKeyUp(函数(){ 如果(输入。长度> 3){ 我的搜索功能(); } });

                      ...也就是说,以一种伪代码的方式,但你明白了。

                      【讨论】:

                        【解决方案19】:

                        您可以按名称 minlength 使用参数,以将搜索限制为 3 个字符:

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

                        【讨论】:

                          【解决方案20】:

                          这适用于 DataTables 版本 1.10.19。它只需要在您的网站模板中包含 js - 对于在不同页面上配置了多个数据表的网站很有用。对于任何缓慢的 xhr 加载表也很有用,在所有当前运行完成之前不会允许任何新的 xhr 请求。使用的搜索功能与插件最初设置search function的方式非常相似。

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

                          【讨论】:

                            【解决方案21】:

                            这里的大多数答案都以某种方式操纵现有的 DataTable 事件绑定,但在花了太长时间试图让这个工作之后,我个人发现,最后我发现的最佳方法是在 @987654321 中发送一个虚拟值ajax调用期间的@参数。

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

                            ##EmptySearch## 字符串只是充当一个不应匹配任何返回数据的值(使用什么完全是个人喜好,但它应该是一个保证不匹配任何数据的字符串)。因为绑定没有被操纵,所有通常的花里胡哨仍然有效,但在搜索大于或等于三个字符之前没有返回任何有意义的内容。诚然,这并不理想,宁愿根本不发出服务器请求,但(在我看来)这是最简单的方法,不会破坏 DataTable 搜索的现有功能。

                            【讨论】:

                              【解决方案22】:

                              需要修改jquery.datatables.js

                              ----- 更新 当然你可以检查长度> 3,但我认为你仍然需要一个计时器。如果您有大量数据,您不希望在每次字符更新后都对其进行过滤。

                              在这个方法中:

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

                              向按键添加一个计时器,如其中一个答案所示。

                              那就去这个网站http://jscompress.com/

                              通过您修改后的代码,js 将被缩小。

                              【讨论】:

                              • 您好,谢谢 - 但我可以添加 $('.input').length > 3 或 $(#input').length > 3 检查而不是计时器吗?我不确定如何引用搜索字段。
                              • 当然你可以检查长度 > 3,但我认为你仍然需要一个计时器。如果您有大量数据,您不希望在每次字符更新后都对其进行过滤。 我已通过正确检查 3 个字符以上的长度来更新答案。添加计时器是下一个有价值的步骤。
                              【解决方案23】:

                              您是否有理由不只检查“更改”的长度?

                              $('.input').change(function() {
                                if( $('.input').length > 3 ) {
                                   //do the search
                                }
                              });
                              

                              【讨论】:

                              • 因为 DataTables 已经绑定到这个,并且自动调用搜索。你必须拦截/改变绑定。
                              猜你喜欢
                              • 2014-05-08
                              • 2019-02-27
                              • 1970-01-01
                              • 2015-01-02
                              • 2013-07-27
                              • 2023-03-17
                              • 1970-01-01
                              • 2021-05-14
                              • 2015-10-13
                              相关资源
                              最近更新 更多