Ainda não tem acesso? Estude com a gente! Matricule-se
Ainda não tem acesso? Estude com a gente! Matricule-se

Solucionado (ver solução)

Usando o fadeOut no filtro

Eu quis fazer com que as linhas não sumissem de uma vez só quando você digitava no filtro. Para isso, ao invés de adicionar somente a classe "invisivel" às linhas que não possuíam o conteúdo do campo, adicionei também a elas a classe "fadeOut" - feita nas lições anteriores - e coloquei a instrução que adiciona a classe "invisivel" dentro de um setTimeOut para dar tempo da transição ocorrer.

O problema é que enquanto a transição acontece nesses 0.5s, os eventos que ocorrem nesse intervalo não são percebidos pelo script (já que o setTimeOut está dentro da função que trata particularmente cada evento). Assim, se eu seguro o Backspace para apagar o nome que digitei no filtro, as linhas não voltam inteiramente pois ele interpreta que ainda há um caractere lá, já que o evento de apagá-lo passou desapercebido.

Há uma maneira de armazenar os eventos que acontecem enquanto eu ainda estou tratando um?

13 respostas

Fala ai Eric, tudo bem? Falando assim sem ver o funcionamento ou problema é bem complicado.

Consegue compartilhar o projeto completo? Assim eu consigo subir ele aqui e visualizar o problema.

Pode compartilhar através do Github ou Google Drive (zipado).

Fico no aguardo.

Fala ai Eric, tudo bem? Falando assim sem ver o funcionamento ou problema é bem complicado.

Consegue compartilhar o projeto completo? Assim eu consigo subir ele aqui e visualizar o problema.

Pode compartilhar através do Github ou Google Drive (zipado).

Fico no aguardo.

Matheus, acho que só com esse pedaço aqui dá pra entender:

var campoFiltro = document.querySelector(".filtrar-tabela");

campoFiltro.addEventListener("input", function(){

  var valorAtual = this.value;

  var pacientes = document.querySelectorAll(".paciente");

  pacientes.forEach(function(paciente){

    var nomeDoPaciente = paciente.querySelector(".info-nome").textContent;

    var expressao = new RegExp(valorAtual,"i");

    if(valorAtual.length == 0 || expressao.test(nomeDoPaciente)) {

      paciente.classList.remove("fadeOut");

      paciente.classList.remove("invisivel");

    }

    else{

      paciente.classList.add("fadeOut");

      setTimeout(function(){paciente.classList.add("invisivel")}, 500);

    }

  })

})

Repare que na função anônima que trata o evento, caso as condições sejam atendidas, há uma instrução de adição de classe dentro de um SetTimeOut. O problema que está acontecendo é que durante os 500 mS do SetTimeOut que está inserido na função, os eventos que acontecem não são ouvidos, já que o script pára pra esperar esse tempo.

Graças a isso, se eu limpo o campo rápido demais, o script não percebe todos os eventos e interpreta que ainda há caracteres lá que já foram limpos na realidade.

Queria saber se há uma forma de armazenar os eventos enquanto o setTimeOut acontece ou se há outra forma de fazer um atraso de instrução sem que o script pare para todo o resto.

Creio que há um erro de lógica no seu código na linha:

if(valorAtual.length == 0 || expressao.test(nomeDoPaciente)) {

ela diz: "se o input estiver vazio ou o nome do paciente tiver contido na input" então "esconda o paciente"

o certo seria: "se o input estiver vazio ou o nome do paciente NÃO tiver contido na input" então "esconda o paciente"

pra corrigir substitua aquela linha por essa:

if(valorAtual.length == 0 || !expressao.test(nomeDoPaciente)) {

com essa exclamação podemos negar a afirmação e resolver o problema.

Fala Eric, a resposta do Murilo deu certo? Conseguiu resolver o problema.

Ficamos no aguardo.

Negativo, Matheus. Acabou que pulei para outro curso e esqueci de voltar aqui. Mas não há erro de lógica. Ao contrário do que o Murilo colocou, a linha diz: "se o input estiver vazio ou o nome do paciente tiver contido na input" então "retire as classes que escondem o paciente (ou seja, mostra o paciente)". O funcionamento do script está correto. O meu problema é de outra natureza, especificado acima. Já entendi o que está acontecendo, só não sei como ultrapassar esse obstáculo.

Por isso perguntei se há uma forma de armazenar os eventos enquanto o setTimeOut acontece ou se há outra forma de fazer um atraso de instrução sem que o script pare para todo o resto.

Entendi, é, nesse caso eu precisaria ver o problema acontecendo e estar com o projeto.

Falando assim sem ver é bem complicado, pois esse problema pode ter N soluções.

Se quiser compartilha o projeto completo comigo e me fala como simulo o problema.

Pode compartilhar através do Github ou Google Drive (zipada).

Espero ter ajudado.

Matheus,

segue o projeto:

https://github.com/EricBCF/Alura-3D/raw/master/introducao-javascript.zip

Fala ai Eric, dei uma olhada no projeto.

O que você pode estar fazendo para resolver esse problema é aplicar um debounce pattern.

Segue um post sobre o mesmo (caso não conheça):

https://blog.matheuscastiglioni.com.br/previnindo-multiplas-requisicoes-com-debounce/

Seu código ficaria mais ou menos assim:

var campoFiltro = document.querySelector(".filtrar-tabela");
var timeout;

campoFiltro.addEventListener("input", function() {
  clearTimeout(timeout);
  timeout = setTimeout(() => {
    var valorAtual = this.value;
    var pacientes = document.querySelectorAll(".paciente");

    pacientes.forEach(function(paciente) {
      var nomeDoPaciente = paciente.querySelector(".info-nome").textContent;

      var expressao = new RegExp(valorAtual, "i");

      if (valorAtual.length == 0 || expressao.test(nomeDoPaciente)) {
        paciente.classList.remove("fadeOut");

        paciente.classList.remove("invisivel");
      } else {
        paciente.classList.add("fadeOut");

        setTimeout(function() {
          paciente.classList.add("invisivel");
        }, 500);
      }
    });
  }, 250);
});

Acho que vai resolver o problema.

Espero ter ajudado.

Matheus, eu entendi a filosofia de funcionamento da técnica (muito legal, diga-se de passagem), porém não compreendi a mecânica.

Quando chega um evento, ele zera o SetTimeOut e então o dispara com um tempo de 250 mS para, após esse tempo, executar a função.

A dúvida que eu tenho é se, enquanto o SetTimeOut está acontencendo, um novo evento for gerado, ele executa o ClearTimeOut mesmo estando no meio da execução do SetTimeOut?

solução

Fala Eric, vamos lá:

A dúvida que eu tenho é se, enquanto o SetTimeOut está acontencendo, um novo evento for gerado, ele executa o ClearTimeOut mesmo estando no meio da execução do SetTimeOut?

A ideia é agendar a execução de uma tarefa para daqui X tempo.

Imagine que a gente digita no campo, então, ao invés de executarmos alguma função imediatamente a cada teclado digitada, nós agendamos uma execução de alguma função para daqui um segundo por exemplo.

Se no o usuário em menos de um segundo digitar novamente, o agendamento anterior é cancelado e agendamos um novo. Caso outra tecla seja digitada em menos de um segundo o mesmo processo é refeito.

Caso nenhum tecla seja digitada em menos de um segundo, ai sim a função em si é executada, se por acaso ele digitar uma nova tecla após um segundo e um milésimo, a função vai ser executada mesmo assim, ou seja, deu o prazo de um segundo ela vai executar.

Fez sentido?

Espero ter ajudado.

Fez sim, Matheus. Muito obrigado!

Magina Eric, sempre que precisar não deixe de criar suas dúvidas.

Abraços e bons estudos.