Detección de cambio de área de texto

132

¿Cómo detecto el evento de cambio en textarea usando javascript?
Estoy tratando de detectar cuántos caracteres quedan disponibles mientras escribes.

Intenté usar el evento onchange, pero parece que solo funciona cuando el foco está fuera.

Teepusink
fuente

Respuestas:

97

Necesitará usar onkeyup y onchange para esto. El cambio evitará el pegado del menú contextual, y el encendido se activará por cada pulsación de tecla.

Vea mi respuesta sobre Cómo imponer maxlength en textArea para obtener un ejemplo de código.

Josh Stodola
fuente
3
Solo quería enfatizar lo que Josh ya dijo, que debería usar keyup, no keydown para esto: keydown parece ser llamado antes de que el cambio se realice en el área de texto, por lo que usará la longitud incorrecta (y no ' Realmente no sé qué tan apagado está: podría estar escribiendo o eliminando, y podría tener texto seleccionado, lo que significa que es más que solo +/- 1).
brianmearns
65
Estoy dando un -1 aquí, lo siento! onkeyupEs un evento terrible para la detección de entrada. Uso oninputy onpropertychange(para soporte de IE).
Andy E
66
El "único" problema se onchangeestá NO activa cuando se produce un menú contextual cortar / pegar.
Tom
44
Es mucho más receptivo usar onkeydown y setTimeout para obtener una detección de cambios instantánea en lugar de esperar a que se libere la clave. Si también necesita atrapar cortar y pegar, use los eventos de cortar y pegar.
Kevin B
1
Advertencia: onkeyup puede darte problemas. Ejemplo: supongamos que solo debe hacer algo si los contenidos de entrada cambiaron. Si asume que un keyup cambiará la entrada, no es cierto. Poner foco en la entrada. Use la "pestaña" para pasar al siguiente campo. Ahora use "shift + tab" para volver a la entrada. keyup se dispara pero la entrada no fue cambiada por el usuario.
Zig Mandel
117

Es 2012, la era posterior a la PC está aquí, y todavía tenemos que luchar con algo tan básico como esto. Esto debería ser muy simple .

Hasta el momento en que se cumpla ese sueño, esta es la mejor manera de hacerlo, navegador cruzado: use una combinación de eventos inputyonpropertychange , de esta manera:

var area = container.querySelector('textarea');
if (area.addEventListener) {
  area.addEventListener('input', function() {
    // event handling code for sane browsers
  }, false);
} else if (area.attachEvent) {
  area.attachEvent('onpropertychange', function() {
    // IE-specific event handling code
  });
}

El inputevento se encarga de IE9 +, FF, Chrome, Opera y Safari , y onpropertychangese encarga de IE8 (también funciona con IE6 y 7, pero hay algunos errores).

La ventaja de usar inputy onpropertychangees que no se disparan innecesariamente (como al presionar las teclas Ctrlo Shift); así que si desea ejecutar una operación relativamente costosa cuando el contenido del área de texto cambia, este es el camino a seguir .

Ahora IE, como siempre, hace un trabajo a medias de apoyar esto: inputni onpropertychangedispara en IE cuando los caracteres se eliminan del área de texto. Entonces, si necesita manejar la eliminación de caracteres en IE, use keypress(en lugar de usar keyup/ keydown, porque se activan solo una vez, incluso si el usuario presiona y mantiene presionada una tecla).

Fuente: http://www.alistapart.com/articles/expanding-text-areas-made-elegant/

EDITAR: Parece que incluso la solución anterior no es perfecta, como se señala correctamente en los comentarios: la presencia de la addEventListenerpropiedad en el área de texto no implica que esté trabajando con un navegador sano; Del mismo modo, la presencia de la attachEventpropiedad no implica IE. Si desea que su código sea realmente hermético, debería considerar cambiarlo. Ver el comentario de Tim Down para los punteros.

Vicky Chijwani
fuente
1
Este es el mejor enfoque. No me gustan las inferencias aquí (el soporte del navegador addEventListenerno implica el soporte para el inputevento, o viceversa); detección de características sería mejor. Vea esta publicación de blog para una discusión de esto.
Tim Down
Totalmente de acuerdo con Tim en este caso. oninputes cómo deberíamos hacer esto, pero probablemente no debería usarlo addEventListenercomo prueba para el soporte del navegador. +1 en cualquier caso.
Ben D
1
No estoy de acuerdo, la entrada no se encargará de IE9. Cortar / Pegar a través del menú contextual desafortunadamente también es una entrada, y también lo es el retroceso. No me molesté en probar, pero no apostaría dinero en la apuesta de que IE10 + solucionó ese problema.
Stefan Steiger
1
@StefanSteiger, por eso mi respuesta sugiere también usar el keypressevento para manejar ese caso en IE9 (y posiblemente en versiones posteriores también).
Vicky Chijwani
inputEl controlador de eventos también se puede definir implementando la .oninputpropiedad del objeto.
manejar el
20
  • Para Google-Chrome, la entrada será suficiente (probado en Windows 7 con la versión 22.0.1229.94 m).
  • Para IE 9, oninput capturará todo, excepto el corte a través del menú contextual y la tecla de retroceso.
  • Para IE 8, se requiere onpropertychange para detectar el pegado además de oninput.
  • Para IE 9 + 8, se requiere onkeyup para recuperar el retroceso.
  • Para IE 9 + 8, onmousemove es la única forma en que encontré atrapar el corte a través del menú contextual

No probado en Firefox.

    var isIE = /*@cc_on!@*/false; // Note: This line breaks closure compiler...

    function SuperDuperFunction() {
        // DoSomething
    }


    function SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally() {
        if(isIE) // For Chrome, oninput works as expected
            SuperDuperFunction();
    }

<textarea id="taSource"
          class="taSplitted"
          rows="4"
          cols="50"
          oninput="SuperDuperFunction();"
          onpropertychange="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onmousemove="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onkeyup="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();">
Test
</textarea>
Stefan Steiger
fuente
1
Nombres de funciones increíbles :)
Jonas Gröger
8

Sé que esta no es exactamente tu pregunta, pero pensé que podría ser útil. Para ciertas aplicaciones, es bueno tener activada la función de cambio no cada vez que se presiona una tecla. Esto se puede lograr con algo como esto:

var text = document.createElement('textarea');
text.rows = 10;
text.cols = 40;
document.body.appendChild(text);

text.onkeyup = function(){
var callcount = 0;
    var action = function(){
        alert('changed');
    }
    var delayAction = function(action, time){
        var expectcallcount = callcount;
        var delay = function(){
            if(callcount == expectcallcount){
                action();
            }
        }
        setTimeout(delay, time);
    }
    return function(eventtrigger){
        ++callcount;
        delayAction(action, 1200);
    }
}();

Esto funciona probando si un evento más reciente se ha disparado dentro de un cierto período de retraso. ¡Buena suerte!

usuario45743
fuente
1
¡+1 por acción retardada 'estrangulamiento'! Yo uso algo similar en mi aplicación.
psulek
7

Sé que esta pregunta era específica de JavaScript, sin embargo, parece que no hay una forma buena y limpia de detectar SIEMPRE cuándo un área de texto cambia en todos los navegadores actuales. He aprendido que jquery se ha encargado de nosotros. Incluso maneja los cambios del menú contextual en las áreas de texto. Se utiliza la misma sintaxis independientemente del tipo de entrada.

    $('div.lawyerList').on('change','textarea',function(){
      // Change occurred so count chars...
    });

o

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });
Tim Duncklee
fuente
44
Descubrí que el evento de cambio no era más consistente con jQuery que con JS simple. Usé jQuery's bind("input cut paste"...y funciona de maravilla: escribir, cortar y pegar usando el teclado o el menú contextual; incluso arrastrar / soltar texto.
Lawrence Dol
2
Desafortunadamente, FF no dispara changeeventos para textarea.
dma_k
4

Puede escuchar el evento sobre el cambio de área de texto y hacer los cambios según lo desee. Aquí hay un ejemplo.

(() => {
	const textArea = document.getElementById('my_text_area');
  textArea.addEventListener('input', () => {
    let textLn =  textArea.value.length;
    if(textLn >= 100) {
      textArea.style.fontSize = '10pt';
    }

  })
})()
<html>
<textarea id='my_text_area' rows="4" cols="50" style="font-size:40pt">
This text will change font after 100.
</textarea>
</html>

Pankaj Manali
fuente
1

Keyup debería ser suficiente si se combina con la validación de entrada HTML5 / atributo de patrón. Por lo tanto, cree un patrón (regex) para validar la entrada y actuar sobre el estado .checkValidity (). Algo como a continuación podría funcionar. En su caso, desearía que una expresión regular coincida con la longitud. Mi solución está en uso / habilitada para demostración en línea aquí .

<input type="text" pattern="[a-zA-Z]+" id="my-input">

var myInput = document.getElementById = "my-input";

myInput.addEventListener("keyup", function(){
  if(!this.checkValidity() || !this.value){
    submitButton.disabled = true;
  } else {
    submitButton.disabled = false;
  }
});
Ronnie Royston
fuente
0

Código que he usado para IE 11 sin jquery y solo para un único área de texto:

Javascript:

// Impede que o comentário tenha mais de num_max caracteres
var internalChange= 0; // important, prevent reenter
function limit_char(max)
{ 
    if (internalChange == 1)
    {
        internalChange= 0;
        return;
    }
    internalChange= 1;
    // <form> and <textarea> are the ID's of your form and textarea objects
    <form>.<textarea>.value= <form>.<textarea>.value.substring(0,max);
}

y html:

<TEXTAREA onpropertychange='limit_char(5)' ...
Rogério Silva
fuente
-1

Prueba este. Es simple, y desde 2016 estoy seguro de que funcionará en la mayoría de los navegadores.

<textarea id="text" cols="50" rows="5" onkeyup="check()" maxlength="15"></textarea> 
<div><span id="spn"></span> characters left</div>

function check(){
    var string = document.getElementById("url").value
    var left = 15 - string.length;
    document.getElementById("spn").innerHTML = left;
}
defecto
fuente
Entonces obtienes url por id, pero no se muestra en tu código.
AbsoluteƵERØ
-8

Lo mejor que puede hacer es configurar una función para que se invoque en un período de tiempo determinado y esta función para verificar el contenido de su área de texto.

self.setInterval('checkTextAreaValue()', 50);
Ico
fuente
77
el sondeo es una muy mala idea. Simplemente destruirá el rendimiento. Además, como otros publicados, existe alguna solución
Pier-Olivier Thibault
2
Este es el siglo XXI. Ningún navegador debería tener problemas para manejar una comparación de cadenas cada 50 ms. Caché sus selectores y esta es una solución perfectamente aceptable.
nulabilidad