2009-10-25 21 views
30

Tengo un área de texto donde las personas ingresan texto (naturalmente), y quiero hacerlo para que se haga una solicitud de AJAX de vez en cuando para obtener sugerencias sobre el tema de texto (como preguntas relacionadas con el desbordamiento de pila, pero para un área de texto, no una entrada de texto). El problema es que no puedo hacer una solicitud de AJAX en cada pulsación de tecla (sería inútil y consume muchos recursos), y no estoy seguro de cuál sería la forma más eficiente de hacerlo (cada X palabras? Cada X segundos ? ¿o algo mas?).Cómo desencadenar un evento onkeyup que se retrasa hasta que un usuario pausa su tipado?

¿Cuál sería la mejor manera de hacerlo?

Gracias de antemano.

+1

posible duplicado de [jQuery .keyup () retraso] (http: // stackoverflow.com/questions/1909441/jquery-keyup-delay) – kenorb

+0

@kenorb esta pregunta era realmente la primera, y tu referencia fue considerada como un duplicado de estas preguntas, pero los administradores no quisieron cerrar la pregunta porque el título era mejor y tiene sobre 132931 puntos de vista, que es bastante notable. – Adam

+0

No importa que este sea más antiguo, el otro tenga más votos y vistas, consulte: [¿Debo marcar una pregunta como duplicada si ha recibido mejores respuestas?] (Http://meta.stackoverflow.com/q/ 251938/55075). El título se puede editar siempre a la mejor. Pueden estar siempre [fusionados] (http://meta.stackexchange.com/a/147651/191655). – kenorb

Respuesta

60

Puede combinar un controlador de eventos keypress con para enviar una solicitud Ajax una cantidad de tiempo establecida después de una pulsación de tecla, cancelar y reiniciar el temporizador si se produce otra pulsación de tecla antes de que termine el temporizador. Asumiendo que tiene un área de texto con id 'myTextArea' y una función de devolución de llamada Ajax llamada doAjaxStuff:

function addTextAreaCallback(textArea, callback, delay) { 
    var timer = null; 
    textArea.onkeypress = function() { 
     if (timer) { 
      window.clearTimeout(timer); 
     } 
     timer = window.setTimeout(function() { 
      timer = null; 
      callback(); 
     }, delay); 
    }; 
    textArea = null; 
} 

addTextAreaCallback(document.getElementById("myTextArea"), doAjaxStuff, 1000); 
+2

Esta es la forma "correcta" generalmente aceptada de hacer esto. Bien dicho. –

+0

Gracias Tim, brillante solución: D –

+3

use onkeyup si desea poder capturar eventos de tecla de retroceso. – barkmadley

0

Si está interesado en soluciones jQuery, jQuery Suggest es una buena implementación.

No tiene sentido reinventar la rueda cada vez.

+0

Esto no funciona para mí, ya que no quiero actualizar el área de texto ni nada con las sugerencias realizadas. Solo quiero hacer una solicitud de AJAX para obtener el contenido de otro elemento en la página, cada pulsación de tecla X o cada X segundos que esté escribiendo el usuario, o algo así. Me preguntaba cuál sería la opción más eficiente. –

1

Usaría personalmente un setInterval que controlaría los cambios en el área de texto y solo realizaría devoluciones de llamada AJAX cuando detecte que se realiza un cambio. cada segundo debe ser lo suficientemente rápido y lento.

+0

Esto requiere que setInterval se ejecute para siempre. La solución de Tim es mucho más elegante, solo se ejecuta cuando alguien realmente está interactuando con el cuadro de texto. –

+0

ejecutar para siempre hasta que la página está descargada. Además, si desea proporcionar algunos comentarios a medida que el usuario escribe, mi solución es mejor, ya que tiene la posibilidad de enviar una solicitud si el usuario escribe más rápido que una tecla por segundo. No digo que la solución de Tim no sea elegante, pero que en algunos casos no es la solución según la aplicación. – barkmadley

9

Otra alternativa es utilizar un pequeño plugin jQuery llamado bindWithDelay. Utiliza la misma técnica setTimeout que tiene la respuesta aceptada, pero maneja los tiempos de espera de forma transparente para que su código sea un poco más fácil de leer. El source code se puede ver en github.

$("#myTextArea").bindWithDelay("keypress", doAjaxStuff, 1000) 
0

Si está utilizando esta funcionalidad mucho alrededor del sitio y no desea hacer un seguimiento de todos los árbitros, etc. entonces SetTimeOut i envasados ​​esto en un plugin disponible here.

El complemento agrega algunas opciones al método normal $ .ajax para almacenar en búfer y cancelar llamadas ajax anteriores.

2

Si está utilizando underscore.js puede usar el debounce function.

Ejemplo (jQuery utiliza para keyup):

$('#myTextArea').keyup(_.debounce(function(){ 
    alert('hello'); 
}, 500)); 
4

Lo que estamos buscando se llama debouncing. Aquí es un algoritmo genérico en JavaScript orígenes:

function debounce(fn, duration) { 
    var timer; 
    return function() { 
    clearTimeout(timer); 
    timer = setTimeout(fn, duration) 
    } 
} 

Y aquí está un ejemplo de cómo usarlo con un onkeyup evento:

function debounce(fn, duration) { 
 
    var timer; 
 
    return function(){ 
 
    clearTimeout(timer); 
 
    timer = setTimeout(fn, duration); 
 
    } 
 
} 
 

 
$(function(){ 
 
    
 
    $('#txtSearch').on('keyup', debounce(function(){ 
 
    
 
    alert('You paused your typing!'); 
 
    
 
    }, 500)); 
 
    
 
});
input{ 
 
    padding:.5em; 
 
    font-size:16px; 
 
    width:20em; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<input id="txtSearch" placeholder="Type here" />

Cuestiones relacionadas