Cómo detectar el contenido de un cuadro de texto ha cambiado

417

Quiero detectar cada vez que el contenido de un cuadro de texto ha cambiado. Puedo usar el método de teclado, pero eso también detectará las pulsaciones de teclas que no generan letras, como las teclas de flecha. Pensé en dos métodos para hacer esto usando el evento keyup:

  1. Compruebe explícitamente si el código ASCII de la tecla presionada es una letra \ retroceso \ eliminar
  2. Use los cierres para recordar cuál era el texto en el cuadro de texto antes del golpe de tecla y verifique si esto ha cambiado.

Ambos se ven un poco engorrosos.

olamundo
fuente
77
Sí, capturar keyup para esto es malo. Puedes pegar cosas sin presionar ninguna tecla.
gastador
2
¿Hay alguna posibilidad de que pueda publicar su solución final? Necesito resolver este problema también :)
Matt Dotson
1
o .keyup()evento ... más información aquí: stackoverflow.com/questions/3003879/…
Victor S
1
Ver $ ("# alguna entrada"). ChangePolling () ; para un contenedor que verifica el valor actual y se dispara .change()si ha cambiado.
Joel Purra
necesita verificar esto también stackoverflow.com/a/23266812/3160597
azerafati

Respuestas:

714

Comience a observar el evento 'input' en lugar de 'change'.

jQuery('#some_text_box').on('input', function() {
    // do your stuff
});

... que es agradable y limpio, pero puede extenderse aún más a:

jQuery('#some_text_box').on('input propertychange paste', function() {
    // do your stuff
});
Atul Vani
fuente
12
'live' está en desuso. así que utilice 'on' stackoverflow.com/a/15111970/1724777
NavaRajan
21
La única desventaja de 'input' es que no es compatible con IE <9.
Catfish
55
La entrada es un evento html5 que no es compatible con todos los navegadores. developer.mozilla.org/en-US/docs/Web/API/window.oninput
commonpike
18
También podría cubrir más bases usando: .on ('input propertychange paste', function () {
Graeck
23
¡La única desventaja de IE <9 es que nadie lo usa!
sohaiby
67

Use el evento onchange en HTML / JavaScript estándar.

En jQuery ese es el evento change () . Por ejemplo:

$('element').change(function() { // do something } );

EDITAR

Después de leer algunos comentarios, ¿qué pasa con:

$(function() {
    var content = $('#myContent').val();

    $('#myContent').keyup(function() { 
        if ($('#myContent').val() != content) {
            content = $('#myContent').val();
            alert('Content has been changed');
        }
    });
});
Waleed Amjad
fuente
3
Sí, esto es similar a lo que sugerí en la opción # 2 en mi pregunta. Prefiero los cierres ya que usar un global hará que esta función funcione solo para un cuadro de texto. De todos modos, parece que jquery extraño no tiene una forma más simple de hacer esto.
olamundo
1
De hecho, es extraño, pero dudo que haya una mejor manera de hacerlo. Puede usar setInterval y luego verificar si el contenido ha cambiado cada 0.1 segundos y luego hacer algo. Esto también incluirá pastas de ratón, etc. Pero no suena demasiado elegante.
Waleed Amjad
44
Todavía es posible que el contenido se pueda cambiar sin presionar una tecla, por ejemplo pegando con el mouse. Si te importa esto, teóricamente también podrías detectar eventos del mouse, pero esa configuración es aún más fea. Por otro lado, si está dispuesto a ignorar los cambios controlados por el mouse, esto servirá.
Adam Bellaire
45

El evento 'cambiar' no funciona correctamente, pero la 'entrada' es perfecta.

$('#your_textbox').bind('input', function() {
    /* This will be fired every time, when textbox's value changes. */
} );
schwarzkopfb
fuente
77
Esto funciona perfectamente para mi situación, aunque .onse recomienda el uso de 1.7 en adelante (en lugar de .bind).
Nick
8
OP no especificó la necesidad de compatibilidad entre navegadores. @schwarzkopfb proporcionó una solución. No hay razón para votar porque tienes el representante para hacerlo.
David East
3
@David tampoco especificó qué navegador
ozz
99
@ jmo21 Creo que podemos asumir para el desarrollo web cuando un navegador no es específico, la solución debe ser multifuncional. La norma es compatible con todos los navegadores.
Chris
3
@Chris "La norma es compatible con todos los navegadores", solo si eres un sádico. No hay una buena razón para evitar la bondad HTML5 para el 2% de los usuarios globales en IE 8/9. caniuse.com/#feat=input-event
Yarin
39

Qué tal esto:

<jQuery 1.7

$("#input").bind("propertychange change keyup paste input", function(){
    // do stuff;
});

> jQuery 1.7

$("#input").on("propertychange change keyup paste input", function(){
    // do stuff;
});

Esto funciona en IE8 / IE9, FF, Chrome

Bagre
fuente
1
El problema que tengo con esta respuesta es que se dispara una vez que borras el cuadro de texto, incluso si el valor no cambió. El culpable es el "cambio".
Justin
¿Estás usando Chrome? Parece que es un error con Chrome y no el evento de cambio de jQuery bugs.jquery.com/ticket/9335
Catfish
funciona pero tiene un error menor si hace un console.logvalor del campo, registra dos veces cada vez que ingresa un carácter.
Samuel M.
21

Use los cierres para recordar cuál era el texto en la casilla de verificación antes de presionar la tecla y verifique si esto ha cambiado.

Sí. No tiene que usar cierres necesariamente, pero deberá recordar el valor anterior y compararlo con el nuevo.

¡Sin embargo! Esto todavía no captará todos los cambios, porque hay formas de editar el contenido del cuadro de texto que no implica ninguna pulsación de tecla. Por ejemplo, seleccionando un rango de texto y luego haciendo clic con el botón derecho del mouse. O arrastrándolo. O colocar texto de otra aplicación en el cuadro de texto. O cambiar una palabra a través del corrector ortográfico del navegador. O...

Entonces, si debe detectar cada cambio, debe sondearlo. Podría window.setIntervalverificar el campo contra su valor anterior cada (digamos) segundo. También se podría conectar onkeyupa la misma función de manera que los cambios que están causadas por las pulsaciones de teclas se reflejan más rápido.

¿Incómodo? Si. Pero es eso o simplemente hazlo de la manera normal de cambio de HTML y no intentes actualizar al instante.

bobince
fuente
1
En estos días, el inputevento HTML5 es viable y funciona en las versiones actuales de todos los principales navegadores.
Tim Down
13
$(document).on('input','#mytxtBox',function () { 
 console.log($('#mytxtBox').val());
});

Puede usar el evento 'input' para detectar el cambio de contenido en el cuadro de texto. No use 'live' para vincular el evento ya que está en desuso en Jquery-1.7, así que use 'on'.

NavaRajan
fuente
@NavaRajan Lo probé nuevamente en IE9. Realmente no funciona en el espacio de retroceso.
Flores
No quiero usar .live, pero el problema que tengo es que, de alguna manera, he "regresado al futuro" y en un proyecto mvc3 en el que el líder del equipo quiere quedarse "listo para usar", así que no solo EF 4.0, pero se está utilizando jquery 1.5.1 ASÍ .on () no estaba en 1.5.1, ya que se agregó en jquery versión 1.7 api.jquery.com/on
Tom Stickel
5

Supongo que está buscando hacer algo interactivo cuando cambia el cuadro de texto (es decir, recuperar algunos datos a través de ajax). Estaba buscando esta misma funcionalidad. Sé que usar una solución global no es la más robusta o elegante, pero eso es lo que elegí. Aquí hay un ejemplo:

var searchValue = $('#Search').val();
$(function () {
    setTimeout(checkSearchChanged, 0.1);
});

function checkSearchChanged() {
    var currentValue = $('#Search').val();
    if ((currentValue) && currentValue != searchValue && currentValue != '') {
        searchValue = $('#Search').val();
        $('#submit').click();
    }
    else {
        setTimeout(checkSearchChanged, 0.1);
    }
}

Una cosa clave a tener en cuenta aquí es que estoy usando setTimeout y no setInterval ya que no quiero enviar múltiples solicitudes al mismo tiempo. Esto asegura que el temporizador se "detiene" cuando se envía el formulario y "comienza" cuando se completa la solicitud. Hago esto llamando a checkSearchChanged cuando finaliza mi llamada ajax. Obviamente, puede expandir esto para verificar la longitud mínima, etc.

En mi caso, estoy usando ASP.Net MVC para que pueda ver cómo vincular esto con MVC Ajax también en la siguiente publicación:

http://geekswithblogs.net/DougLampe/archive/2010/12/21/simple-interactive-search-with-jquery-and-asp.net-mvc.aspx

Doug Lampe
fuente
4

Recomendaría echar un vistazo al widget de autocompletar jQuery UI. Manejaron la mayoría de los casos allí, ya que su base de código es más madura que la mayoría de los existentes.

A continuación hay un enlace a una página de demostración para que pueda verificar que funciona. http://jqueryui.com/demos/autocomplete/#default

Obtendrá el mayor beneficio al leer la fuente y ver cómo la resolvieron. Puede encontrarlo aquí: https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.autocomplete.js .

Básicamente lo hacen todo, se unen input, keydown, keyup, keypress, focus and blur. Luego tienen un manejo especial para todo tipo de claves como page up, page down, up arrow key and down arrow key. Se usa un temporizador antes de obtener el contenido del cuadro de texto. Cuando un usuario escribe una tecla que no corresponde a un comando (tecla arriba, tecla abajo, etc.) hay un temporizador que explora el contenido después de aproximadamente 300 milisegundos. Se ve así en el código:

// switch statement in the 
switch( event.keyCode ) {
            //...
            case keyCode.ENTER:
            case keyCode.NUMPAD_ENTER:
                // when menu is open and has focus
                if ( this.menu.active ) {
                    // #6055 - Opera still allows the keypress to occur
                    // which causes forms to submit
                    suppressKeyPress = true;
                    event.preventDefault();
                    this.menu.select( event );
                }
                break;
            default:
                suppressKeyPressRepeat = true;
                // search timeout should be triggered before the input value is changed
                this._searchTimeout( event );
                break;
            }
// ...
// ...
_searchTimeout: function( event ) {
    clearTimeout( this.searching );
    this.searching = this._delay(function() { // * essentially a warpper for a setTimeout call *
        // only search if the value has changed
        if ( this.term !== this._value() ) { // * _value is a wrapper to get the value *
            this.selectedItem = null;
            this.search( null, event );
        }
    }, this.options.delay );
},

La razón para usar un temporizador es para que la IU tenga la oportunidad de actualizarse. Cuando se ejecuta Javascript, la IU no se puede actualizar, por lo tanto, la llamada a la función de retraso. Esto funciona bien para otras situaciones, como mantener el foco en el cuadro de texto (utilizado por ese código).

Por lo tanto, puede usar el widget o copiar el código en su propio widget si no está utilizando jQuery UI (o en mi caso, desarrollando un widget personalizado).

Michael Yagudaev
fuente
2

Me gustaría preguntarle por qué está tratando de detectar cuándo el contenido del cuadro de texto cambió en tiempo real .

Una alternativa sería establecer un temporizador (a través de setIntval?) Y comparar el último valor guardado con el actual y luego restablecer un temporizador. Esto garantizaría detectar CUALQUIER cambio, ya sea causado por teclas, mouse, algún otro dispositivo de entrada que no consideró, o incluso JavaScript cambiando el valor (otra posibilidad que nadie mencionó) desde una parte diferente de la aplicación.

DVK
fuente
mi situación (que me llevó a esta pregunta) es que necesito mostrar un botón 'Actualizar carrito' cuando se cambia la cantidad en un cuadro de texto. el usuario no tiene idea de que necesita perder el foco y de lo contrario no puede ver el botón.
Simon_Weaver el
Lo sentimos, no estoy seguro de que esto responda a la pregunta "¿por qué no buscar diferencias en un horario?". Simplemente verifique con la suficiente frecuencia (cada 1/4 de segundo) y el usuario no notará ninguna diferencia.
DVK el
1

¿Considera usar el evento de cambio ?

$("#myTextBox").change(function() { alert("content changed"); });
Canavar
fuente
55
AFAIK, se dispara solo cuando se pierde el foco del elemento. Alguien que esté familiarizado con los cierres probablemente sepa sobre este. :)
Simon
sí, esto no funcionará: el evento de cambio solo se llama cuando el cuadro de texto pierde el foco. Quiero manejar el cambio justo después de presionar la tecla.
olamundo
1

Use el textchangeevento a través de jQuery shim personalizado para la inputcompatibilidad entre navegadores . http://benalpert.com/2013/06/18/a-near-perfect-oninput-shim-for-ie-8-and-9.html (github bifurcado más recientemente: https://github.com/pandell /jquery-splendid-textchange/blob/master/jquery.splendid.textchange.js )

Esto maneja todas las etiquetas de entrada <textarea>content</textarea>, lo que no siempre funciona con change keyupetc. (!) Solo jQuery on("input propertychange")maneja las <textarea>etiquetas de manera consistente, y lo anterior es una imitación para todos los navegadores que no entienden el inputevento.

<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://raw.githubusercontent.com/pandell/jquery-splendid-textchange/master/jquery.splendid.textchange.js"></script>
<meta charset=utf-8 />
<title>splendid textchange test</title>

<script> // this is all you have to do. using splendid.textchange.js

$('textarea').on("textchange",function(){ 
  yourFunctionHere($(this).val());    });  

</script>
</head>
<body>
  <textarea style="height:3em;width:90%"></textarea>
</body>
</html>

Prueba JS Bin

Esto también maneja pegar, eliminar y no duplica el esfuerzo en el keyup.

Si no usa una cuña, use on("input propertychange")eventos jQuery .

// works with most recent browsers (use this if not using src="...splendid.textchange.js")

$('textarea').on("input propertychange",function(){ 
  yourFunctionHere($(this).val());    
});  
Ber
fuente
0

Hay un ejemplo de trabajo completo aquí .

<html>
<title>jQuery Summing</title>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"> </script>
$(document).ready(function() {
$('.calc').on('input', function() {
var t1 = document.getElementById('txt1');
var t2 = document.getElementById('txt2');
var tot=0;
if (parseInt(t1.value))
tot += parseInt(t1.value);
if (parseInt(t2.value))
tot += parseInt(t2.value);
document.getElementById('txt3').value = tot;
});
});
</script>
</head>
<body>
<input type='text' class='calc' id='txt1'>
<input type='text' class='calc' id='txt2'>
<input type='text' id='txt3' readonly>
</body>
</html>
worldofjr
fuente
0

Algo como esto debería funcionar, principalmente porque focusy focusoutterminaría con dos valores separados. Estoy usando dataaquí porque almacena valores en el elemento pero no toca el DOM. También es una manera fácil de almacenar el valor conectado a su elemento. También podría usar fácilmente una variable de mayor alcance.

var changed = false;

$('textbox').on('focus', function(e) {
    $(this).data('current-val', $(this).text();
});

$('textbox').on('focusout', function(e) {
    if ($(this).data('current-val') != $(this).text())
        changed = true;
    }
    console.log('Changed Result', changed);
}
smcjones
fuente
0

Este código detecta cada vez que el contenido de un cuadro de texto ha cambiado por el usuario y modificado por el código Javascript.

var $myText = jQuery("#textbox");

$myText.data("value", $myText.val());

setInterval(function() {
    var data = $myText.data("value"),
    val = $myText.val();

    if (data !== val) {
        console.log("changed");
        $myText.data("value", val);
    }
}, 100);
Sandeep Yadav
fuente