Implementando valueChangeListener com JSF

Olá pessoal, hoje eu irei compartilhar com vocês uma experiência que tive trabalhando em um projeto, no qual tive que implementar um comportamento de “onchange” em um componente selectOneMenu do JSF 1.2. A princípio a implementação me parecia fácil e bem sugestiva, no entanto, após alguns testes pude perceber que uma “cilada” estaria me surpreendendo: o evento por trás do atributo “valueChangeListener” não executa como esperado!
Tal problema me exigiu alguns esforços para se chegar a uma solução plausível. Creio que este tipo de implementação gere dúvidas também há muitos outros desenvolvedores e, portanto, seguem alguns esclarecimentos:
Tentarei ilustrar o problema com um exemplo de um selectOneMenu que realiza a listagem de carros de acordo com a marca selecionada:
Bom, o primeiro entrave encontrado foi em relação à submissão do formulário: ela não é realizada na alteração da selectOneMenu sem que coloquemos o “onchange=’submit()’” explicitamente!
À primeira vista o código acima parece então sugerir que, ao se alterar uma opção do selectOneMenu, o método declarado no atributo valueChangeListener será invocado. Ah, eis a cilada!
Neste momento, você pode estar me perguntando: mas por que não funcionaria? Eis o segredo: simplesmente porque o método declarado no valueChangeListener é chamado ANTES dos métodos setters do managed-bean serem chamados! Isso implica que, qualquer alteração que você realize nas variáveis no seu método em valueChangeListener seriam sobreescritas quando os setters fossem chamados. E se caso tentassemos pular essas chamadas aos métodos setters invocando “FacesContext.getCurrentInstace.renderResponse()” no método valueChangeListener, simplesmente estariamos pulando também as chamadas aos getters, o que impediria da mesma maneira de exibirmos os valores atualizados na nossa view. Então o que fazer?
Ok, para solucionar nós temos 3 soluções básicas:
1 – Podemos forçar o JSF a recriar a view:
FacesContext context = FacesContext.getCurrentInstance();
// Redireciona para a pagina a mesma página.
context.getApplication().getNavigationHandler().handleNavigation(
context, null, "listarCarros");
E no arquivo faces-config.xml:

2 – Podemos mover o ciclo de vida do JSF à fase de atualização do modelo:
public void listarCarrosMarcaSelecionada(ValueChangeEvent event){
// busca dos carros aqui...
...
PhaseId phaseId = event.getPhaseId();
if (phaseId.equals(PhaseId.ANY_PHASE)){
event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES);
event.queue();
}
}
3 – Podemos criar nosso próprio UIComponent no managed-bean usando “binding” e do método valueChangeListener poderiamos alterá-lo invocando o método “setMethod()”, pois, quando alteramos um UIComponent diretamente, o JSF automaticamente invoca os métodos getters para a atualização da view. Mas ainda sim teriamos que concluir o método invocando “FacesContext.getCurrentInstance().renderResponse()” para forçar a nova renderização.
Para o projeto em que estou, a primeira alternativa foi a adotada pois me pareceu a mais simples e no momento atenderia ao meu propósito. Existem também algumas soluções utilizando ajax, como por exemplo com a implementação do Ajax4JSF que também se mostram interessantes, mas eu não poderia utilizar devido a alguns motivos particulares do projeto.
Bom, então é isso pessoal, ficam aqui as dicas. Espero ter ajudado. Até a próxima!
.
Implementando valueChangeListener com JSF

11 thoughts on “Implementando valueChangeListener com JSF

  • 22 de outubro de 2010 at 20:30
    Permalink

    poxa realmente funcionou man! Ótima tacada, parabéns.

  • 25 de outubro de 2010 at 11:59
    Permalink

    Obrigado pelo retorno Traks! Fico feliz em ter ajudado!

    Para matar a minha dúvida e enriquecer ainda mais este post, você poderia nos dizer qual das 3 opções você usou e porque a escolheu?

    Abraços!

    Eduardo Negrão- portalengenhariadesoftware.blogspot.com

    .

  • 29 de outubro de 2010 at 11:57
    Permalink

    legal, so completando no JSF2 A tag f:ajax resolve isto

  • 7 de outubro de 2011 at 15:14
    Permalink

    Estou num projeto JSF 1 e bati muito a cabeça antes de achar a solução no seu site. Uma puta gambiarra, ou melhor, alternativa técnica mas resolve. Valeu pelas dicas!

  • 20 de outubro de 2011 at 14:25
    Permalink

    É isso mesmo. São os meus dois blogs. Também mantenho como co-autor o Portal do Arquiteto. Os dois artigos são de minha autoria! 😉

  • 4 de julho de 2012 at 19:04
    Permalink

    Parabéns, excelente explicação … E muito útil!

  • 1 de agosto de 2012 at 19:27
    Permalink

    fera eu estu com u mproblema parecido com este so que eu tenho varios inputs e tenho atualiza-los constantemente, por isso tenho q usar o valueChangeListener, mas nesta pagina enho tbm varios required.

    O que acontece é quando do o submit ele da erro no requirid. como fazer ele dar o submit somente no input, é possivel?

  • 22 de agosto de 2012 at 18:20
    Permalink

    Headshot… hauahuahuaha

Deixe uma resposta

O seu endereço de e-mail não será publicado.