Boa tarde, estou fazendo uma aplicação que possui um campo de busca de ruas
que conforme o usuario digita o nome da rua um componente select mostra as ruas
com o nome parecido
consegui fazer numa boa com f:ajax o problema é que preciso fazer agora
uma “aggregation”, ou seja, quero que não ocorra a busca a cada tecla que o
usuario digita para não sobrecarregar o servidor, quero apenas de 1 em 1 segundos
ou algo parecido.
consegui fazer, mas o componente não é renderizado na hora certa (o response do ajax
é executado antes do método terminar).
alguem tem alguma noção de como fazer esse aggregation?
O primefaces possui um elemento chamando <p:poll> e ele próprio faz as requisições ajax de acordo com o tempo estabelecido.
Eu sei que tem outro framework que tem um componente com o mesmo comportamento, mas não sei dizer qual;
Se tu não esta utilizando nenhum framework, voce tera que fazer isso na unha. Um meio de tu fazer isso seria através de js dar um setInterval() com alguma função que verifique de alguma maneira se o método já terminou, e apartir disso realizar a requisição ajax.
[quote=Ygor]O primefaces possui um elemento chamando <p:poll> e ele próprio faz as requisições ajax de acordo com o tempo estabelecido.
Eu sei que tem outro framework que tem um componente com o mesmo comportamento, mas não sei dizer qual;
Se tu não esta utilizando nenhum framework, voce tera que fazer isso na unha. Um meio de tu fazer isso seria através de js dar um setInterval() com alguma função que verifique de alguma maneira se o método já terminou, e apartir disso realizar a requisição ajax.
Se tu puder decorrer mais sobre o seu problema…[/quote]
No próprio primefaces tem o AutoComplete que faz isso.
É verdade!
Tinha me esquecido deste componente. Muito mais elegante do que ficar POGeando por ae hehehehe!
Olhando na documentação dele, ele possui os atributos ‘minQueryLength’ e ‘queryDelay’ que se encaixam perfeitamente neste problema.
Agora se nao poder utilizar o Prime, não consigo pensar em outra maneira se não em JavaScript
Obrigado por ambas as respostas,
antes de vocês responderem eu cogitei em fazer com algum framework
mas na empresa onde eu trabalho não é insentivado o uso de frameworks fora dos padrões,
eu uso apenas JSF 2 e JPA.
por isso optei por fazer em javascript, oque na minha opnião não é a melhor maneira.
estou tendo alguns problemas simples de javascript mas já consegui fazer oque eu precisava.
var token;
var ultimoFocus; //só estou usando esta variavel por problemas de perder o focus ao re-renderizar
function aggregate(elemento, render, increment) {
//função para retardar as requisições via ajax ao servidor para que não
//haja sobrecarga ao enviar várias ao mesmo tempo sem necessidade
window.clearTimeout(token);
//remove o setTimeOut anterior removendo a tarefa ainda não realizada
var send = function send() {
mojarra.ab(elemento, elemento.event, 'keyup', '@this',render);
//função gerada pelo f:ajax
//não é possivel passar o listener como parametro
//infelizmente esse render não funciona com o
//id especificado no facelet, aceita apenas o
//id gerado pelo JSF
setUltimoFocus(elemento);
};
token = window.setTimeout(send, increment);
//adiciona um atraso antes de realizar o send
}
function setUltimoFocus(elemento){
ultimoFocus = elemento.id;
}
function focarNoUltimo(){
if(ultimoFocus!=null){
el = document.getElementById(ultimoFocus);
el.focus();
el.value +=""; //preciso desta gambiarra por causa do chrome que seleciona o texto além de focar
}
}
jsf.ajax.addOnEvent(function(data) {
//esta função é executada após o request - estou focando o elemento novamente neste caso
focarNoUltimo();
});
Bean (SemCookiesBean.java)
@ManagedBean
@SessionScoped
public class SemCookiesBean {
private String rua;
private List<Cep> ruas;
private String ruaBusca;
private String ultimaRuaBusca; //para o controle de requisições, não queremos a mesma busca várias vezes
private long tempoUltimaRuaBusca; //não queremos que o usuario faça mais do que 1 busca por segundo
@EJB
BancoDeDados bd;
public void setRuaBusca(String ruaBusca) {
this.ruaBusca = ruaBusca;
popularApartirDeRuaBusca();
}
//é acessado apenas pelo setRuaBusca por não estarmos usando f:ajax e não temos a possibilidade de passar um listener
// ao invéz de f:ajax utilizamos um script para criar um atraso para não haver sobrecarga
public void popularApartirDeRuaBusca(){
//popula a lista de ruas de acordo com o estado, cidade e ruaBusca
if(ultimaRuaBusca == null || !ultimaRuaBusca.equals(ruaBusca)){
if(tempoUltimaRuaBusca == 0 || tempoUltimaRuaBusca + 1000 <= System.currentTimeMillis()){
//apartir daqui é parte do meu sistema e irrelevalte à vocês
if(estado!=null && !estado.isEmpty() && cidade!=null
&& !cidade.isEmpty()
&& removerTipoDoLogradouro(ruaBusca)!=null
&& !removerTipoDoLogradouro(ruaBusca).isEmpty()){
ultimaRuaBusca = ruaBusca;
tempoUltimaRuaBusca = System.currentTimeMillis();
ruas = bd.obterRuas(estado, cidade, removerTipoDoLogradouro(ruaBusca));
} else
ruas = new LinkedList<Cep>();
}
}
}
//outros métodos getters e setters
}
[size=18]é isso aí, este tópico esta aberto para mais sugestões de Aggregation[/size]
Apenas um adendo, creio que não fara diferença nenhuma no resultado do seu código, mas como informação nunca é de mais.
Quando tu regristra uma função nos EventListeners do jsf.ajax
jsf.ajax.addOnEvent(function(data) {
//esta função é executada após o request - estou focando o elemento novamente neste caso
focarNoUltimo();
});
Essa função é chamada tanto no beggin,complete e success da requisição ajax. Se tu quiser que determinada função ocorra apenas em algum estado, a variavel data possui um atributo String chamado status(data.status) que retorna o estado atual da requisição. Ai é só fazer um if (data.status == “success”) {}, muito util quando a gente precisa colocar um gif de load simbolizando um ajaxStatus
nossa muito legal, isso pode ser útil no futuro, por enquanto vou deixar deste jeito
que já esta funcionando, não gosto muito de trabalhar com javascript.
Sim, pode sim. Na verdade é até bom tomar um pouco de cuidado quando tu cadastra essas funções no eventListener por que elas são chamado em qualque requsição ajax. E como não existe um removeEvent() pode se tornar um pouco complicado. Ai tu tera que trabalhar com o atributo data.source que retorna o objeto no qual a requisição ajax foi feita e apartir disso definir qual comportamento realizar.
Os frameworks(Prime) ja possuem uma solução mais elegante, os componentes possuem eventos oncomplete, e as funções sao chamadas no complete referente a requisição ajax do componente eliminando a necessidade de cadastrar um evento numa lista de eventListeners
ps: quando eu digo qualquer requisição ajax, é qualquer mesma. Qualquer componente que tenha um <f:ajax>, mojarra.ab(). jsf.ajax.request() ira fazer uma chamada a essa função.
é eu percebi este comportamento mesmo. Estou convencido de que é uma boa
idéia usar o primeFaces no próximo projeto que precisar de algo sofisticado em ajax.
economiza muito tempo de trabalho usar um framework com a funcionalidade pronta.