Получить текст из поля на клавиатуре, но с задержкой для дальнейшего ввода

У меня есть форма, которая отправляется удаленно, когда различные элементы меняются. В частности, в поле поиска я использую keyup, чтобы определить, когда изменяется текст в поле. Проблема в том, что когда кто-то печатает "курица", то форма отправляется семь раз, при этом учитывается только последний.

Что было бы лучше, это что-то вроде этого

  • обнаружен keyup - начало ожидания (на одну секунду)

  • обнаружен другой ключ - перезапустите время ожидания

  • ожидание заканчивается - получите значение и отправьте форму

прежде чем я уйду и напишу свою собственную версию этого (я действительно бэкэнд-парень с небольшим js, я использую jQuery для всего), есть ли уже существующее решение для этого? Кажется, это было бы общим требованием. Может быть плагин jQuery? Если нет, то какой самый простой и лучший способ кодировать это?

ОБНОВЛЕНИЕ - текущий код добавлен для Дана (ниже)

Дан - это может быть актуально. Один из плагинов jQuery, которые я использую на странице (TableSorter), требует этот файл - "tablesorter/jquery-latest.js", который, если он включен, приводит к той же ошибке с вашим кодом, что и раньше:

jQuery ("input # search"). data ("timeout", null) не определен http‍://192.168.0.234/javascripts/main.js? 1264084467 Строка 11

Может быть, существует какой-то конфликт между различными определениями jQuery? (или что-то)

$(document).ready(function() {
  //initiate the shadowbox player
//  Shadowbox.init({
//    players:  ['html', 'iframe']
//  });
}); 

jQuery(function(){
  jQuery('input#search')
    .data('timeout', null)
    .keyup(function(){
      jQuery(this).data('timeout', setTimeout(function(){
          var mytext = jQuery('input#search').val();
          submitQuizForm();
          jQuery('input#search').next().html(mytext);
        }, 2000)
     )
     .keydown(function(){
       clearTimeout(jQuery(this).data('timeout'));
     });
    });
});

function submitQuizForm(){
  form = jQuery("#searchQuizzes");
  jQuery.ajax({
    async:true, 
    data:jQuery.param(form.serializeArray()), 
    dataType:'script', 
    type:'get', 
    url:'/millionaire/millionaire_quizzes',
    success: function(msg){ 
     // $("#chooseQuizMainTable").trigger("update"); 
    }
  }); 
  return true;
}

Ответы

Ответ 1

Жаль, что я не тестировал это, и это немного от меня, но что-то в этом направлении, надеюсь, сделает трюк. Измените 2000 на сколько угодно миллисекунд между серверами сообщений

<input type="text" id="mytextbox" style="border: 1px solid" />
<span></span>

<script language="javascript" type="text/javascript">
    jQuery(function(){
      jQuery('#mytextbox')
        .data('timeout', null)
        .keyup(function(){
            clearTimeout(jQuery(this).data('timeout'));
            jQuery(this).data('timeout', setTimeout(submitQuizForm, 2000));
        });
    });
</script>

Ответ 2

Здесь ваше фантастическое расширение jquery:

(function($){

$.widget("ui.onDelayedKeyup", {

    _init : function() {
        var self = this;
        $(this.element).keyup(function() {
            if(typeof(window['inputTimeout']) != "undefined"){
                window.clearTimeout(inputTimeout);
            }  
            var handler = self.options.handler;
            window['inputTimeout'] = window.setTimeout(function() {
                handler.call(self.element) }, self.options.delay);
        });
    },
    options: {
        handler: $.noop(),
        delay: 500
    }

});
})(jQuery);

Используйте его так:

    $("input.filterField").onDelayedKeyup({
        handler: function() {
            if ($.trim($(this).val()).length > 0) {
                //reload my data store using the filter string.
            }
        }
    });

Задержка по умолчанию занимает половину секунды.

Ответ 3

Как обновление, я закончил с этим, который, кажется, хорошо работает:

function afterDelayedKeyup(selector, action, delay){
  jQuery(selector).keyup(function(){
    if(typeof(window['inputTimeout']) != "undefined"){
      clearTimeout(inputTimeout);
    }  
    inputTimeout = setTimeout(action, delay);
  });
}

Затем я вызываю это со страницы, на которой находится документ document.ready с

  afterDelayedKeyup('input#search',"submitQuizForm()",500)

Было бы неплохо сделать новое событие jquery, которое использует эту логику, например .delayedKeyup, чтобы идти рядом с .keyup, поэтому я могу просто сказать что-то подобное для отдельного блока document.ready страницы.

  jQuery('input#search').delayedKeyup(function(){
    submitQuizForm();
  });

Но я не знаю, как настроить jquery таким образом. Это хорошая домашняя задача, хотя.

Ответ 4

Хорошая работа, Макс, это было очень полезно для меня! Я сделал небольшое улучшение вашей функции, сделав ее более общей:

function afterDelayedEvent(eventtype, selector, action, delay) {
    $(selector).bind(eventtype, function() {
        if (typeof(window['inputTimeout']) != "undefined") {
            clearTimeout(inputTimeout);
        }
        inputTimeout = setTimeout(action, delay);
    });
}

Таким образом, вы можете использовать его для любого типа событий, хотя, возможно, наиболее полезным здесь является keyup.

Ответ 5

Я знаю, что это старо, но это был один из первых результатов, когда я искал, как сделать что-то подобное, поэтому, хотя я бы поделился своим решением. Я использовал комбинацию предоставленных ответов, чтобы получить то, что мне нужно.

Мне понадобилось настраиваемое событие, которое работало так же, как и существующие события jQuery, и ему нужно было работать с keypress + delete, backspace и enter.

Здесь мой плагин jQuery:

$.fn.typePause = function (dataObject, eventFunc)
    {
        if(typeof dataObject === 'function')
        {
            eventFunc = dataObject;
            dataObject = {};
        }
        if(typeof dataObject.milliseconds === 'undefined')
            dataObject.milliseconds = 500;
        $(this).data('timeout', null)
            .keypress(dataObject, function(e)
            {
                clearTimeout($(this).data('timeout'));
                $(this).data('timeout', setTimeout($.proxy(eventFunc, this, e), dataObject.milliseconds));
            })
            .keyup(dataObject, function(e)
            {
                var code = (e.keyCode ? e.keyCode : e.which);
                if(code == 8 || code == 46 || code == 13)
                    $(this).triggerHandler('keypress',dataObject);
            });
    }

Я использовал $.proxy(), чтобы сохранить контекст в событии, хотя может быть лучший способ сделать это, с точки зрения производительности.

Чтобы использовать этот плагин, просто выполните:

$('#myElement').typePause(function(e){ /* do stuff */ });

или

$('#myElement').typePause({milliseconds: 500, [other data to pass to event]},function(e){ /* do stuff */ });