Detecção de alteração de área de texto

132

Como detecto evento de alteração na área de texto usando javascript?
Estou tentando detectar quantos caracteres restantes estão disponíveis enquanto você digita.

Eu tentei usar o evento onchange, mas isso só aparece quando o foco está fora.

teepusink
fonte

Respostas:

97

Você precisará usar onkeyup e onchange para isso. O onchange impedirá a colagem do menu de contexto e o onkeyup será acionado para cada pressionamento de tecla.

Veja minha resposta em Como impor maxlength no textArea para um exemplo de código.

Josh Stodola
fonte
3
Só queria enfatizar o que Josh já disse, que você deveria usar keyup, e não keydown para isso: keydown parece ser chamado antes que a alteração seja realmente feita na área de texto, portanto, você estará usando o comprimento errado (e você não você realmente não sabe como você está: pode estar digitando ou excluindo e pode ter o texto selecionado, o que significa que é mais do que apenas +/- 1).
Brianmearns
65
Estou dando um -1 aqui, desculpe! onkeyupé um evento terrível para a detecção de entrada. Use oninpute onpropertychange(para suporte do IE).
Andy E
6
O problema "único" NÃOonchange é acionado quando ocorre um recorte / colagem no menu de contexto.
Tom
4
É muito mais responsivo usar onkeydown e um setTimeout para que você obtenha a detecção instantânea de alterações, em vez de esperar que a chave seja liberada. Se você também precisar capturar recortar e colar, use os eventos recortar e colar.
Kevin B
1
Aviso: onkeyup pode causar problemas. Exemplo: digamos que você só deve fazer algo se o conteúdo da entrada for alterado. Se você presumir que um keyup alterará a entrada, isso não é verdade. Coloque o foco na entrada. Use "tab" para ir para o próximo campo. Agora use "shift + tab" para voltar à entrada. o keyup é acionado, mas a entrada não foi realmente alterada pelo usuário.
Zig Mandel
117

Estamos em 2012, a era pós-PC chegou e ainda temos que lutar com algo tão básico quanto isso. Isso deve ser muito simples .

Até que esse sonho seja realizado, eis a melhor maneira de fazer isso, em vários navegadores: use uma combinação dos eventos inputeonpropertychange , da seguinte forma:

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

O inputevento cuida do IE9 +, FF, Chrome, Opera e Safari e onpropertychangecuida do IE8 (também funciona com o IE6 e 7, mas existem alguns bugs).

A vantagem de usar inpute onpropertychangeé que eles não disparam desnecessariamente (como ao pressionar as teclas Ctrlou Shift); portanto, se você deseja executar uma operação relativamente cara quando o conteúdo da área de texto muda, este é o caminho a seguir .

Agora, o IE, como sempre, faz um trabalho sem sentido para apoiar isso: inputnem onpropertychangedispara no IE quando os caracteres são excluídos da área de texto. Portanto, se você precisar lidar com a exclusão de caracteres no IE, use keypress(em vez de usar keyup/ keydown, porque eles são acionados apenas uma vez, mesmo que o usuário pressione e mantenha pressionada uma tecla).

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

EDIT: Parece que até a solução acima não é perfeita, como corretamente apontado nos comentários: a presença da addEventListenerpropriedade na área de texto não implica que você esteja trabalhando com um navegador sensato; Da mesma forma, a presença da attachEventpropriedade não implica IE. Se você deseja que seu código seja realmente hermético, considere mudar isso. Veja o comentário de Tim Down para obter dicas.

Vicky Chijwani
fonte
1
Essa é a melhor abordagem. Não gosto das inferências aqui (o suporte do navegador para addEventListenernão implica suporte para o inputevento ou vice-versa); a detecção de recursos seria melhor. Veja esta postagem do blog para uma discussão sobre isso.
Tim Baixo
Concordo totalmente com Tim neste. oninputé assim que devemos fazer isso, mas você provavelmente não deveria estar usando addEventListenercomo teste para suporte ao navegador. +1 em qualquer caso.
Ben D
1
Discordo, a entrada não cuidará do IE9. Recortar / colar via menu de contexto infelizmente também é uma entrada, assim como o backspace. Não me preocupei em testar, mas não apostaria na aposta que o IE10 + corrigiu esse problema.
precisa saber é o seguinte
1
@StefanSteiger, e é por isso que minha resposta sugere também o uso do keypressevento para lidar com esse caso no IE9 (e possivelmente também em versões posteriores).
Vicky Chijwani
inputO manipulador de eventos também pode ser definido implementando a .oninputpropriedade do objeto
manipula
20
  • Para o Google Chrome, a entrada será suficiente (Testado no Windows 7 com versão 22.0.1229.94 m).
  • Para o IE 9, o oninput irá capturar tudo, exceto cortar através do menu de contexto e backspace.
  • Para o IE 8, a troca de propriedade é necessária para capturar a colagem, além da entrada.
  • Para o IE 9 + 8, onkeyup é necessário para recuperar o backspace.
  • Para o IE 9 + 8, onmousemove é a única maneira que encontrei para cortar o corte via menu de contexto

Não testado no 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
fonte
1
Nomes de funções impressionantes :)
Jonas GRÖGER
8

Sei que essa não é exatamente sua pergunta, mas achei que isso poderia ser útil. Para certas aplicações, é bom que a função de alteração seja acionada nem sempre que uma tecla é pressionada. Isso pode ser alcançado com algo como isto:

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

Isso funciona testando se um evento mais recente foi disparado dentro de um certo período de atraso. Boa sorte!

user45743
fonte
1
+1 para ação atrasada 'limitação'! Eu uso algo semelhante no meu aplicativo.
Psulek
7

Eu sei que essa pergunta era específica para JavaScript, no entanto, parece não haver uma maneira boa e limpa de SEMPRE detectar quando uma área de texto é alterada em todos os navegadores atuais. Aprendi que o jquery cuidou disso para nós. Ele até lida com alterações de menu contextual em áreas de texto. A mesma sintaxe é usada independentemente do tipo de entrada.

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

ou

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });
Tim Duncklee
fonte
4
Eu descobri que o evento de mudança não era mais consistente com o jQuery do que com o JS simples. Eu usei o jQuery bind("input cut paste"...e funciona como um encanto - digitando, recortando e colando usando o teclado ou o menu de contexto; até arraste / solte o texto.
Lawrence Dol
2
Infelizmente, o FF não dispara um changeevento para textarea.
Dma_k 4/08/14
4

Você pode ouvir o evento sobre a alteração da área de texto e fazer as alterações conforme desejado. Aqui está um exemplo.

(() => {
	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
fonte
1

A digitação deve ser suficiente se combinada com o atributo de padrão / validação de entrada HTML5. Portanto, crie um padrão (regex) para validar a entrada e agir de acordo com o status .checkValidity (). Algo como abaixo poderia funcionar. No seu caso, você deseja que uma regex corresponda ao comprimento. Minha solução está em uso / pode ser demo on-line aqui .

<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
fonte
0

Código que usei para o IE 11 sem jquery e apenas para uma única á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);
}

e html:

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

Tente este. É simples e, desde 2016, tenho certeza de que funcionará na maioria dos 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;
}
padrão
fonte
Então você está recebendo o URL pelo ID, mas ele não é mostrado no seu código.
AbsoluteZero
-8

A melhor coisa que você pode fazer é definir uma função a ser chamada em um determinado período de tempo e essa função para verificar o conteúdo da sua área de texto.

self.setInterval('checkTextAreaValue()', 50);
Ico
fonte
7
sondagem é uma péssima idéia. Isso apenas destruirá o desempenho. Além disso, como outros publicado, existem alguns solução
Pier-Olivier Thibault
2
Este é o século XXI. Nenhum navegador deve ter problemas ao lidar com uma comparação de cadeias a cada 50 ms. Coloque em cache seus seletores e esta é uma solução perfeitamente aceitável.
nullability