Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
13
respostas

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.