Implementando valueChangeListener com JSF

Eduardo Negrao 19 de maio de 2009 5

Olá pessoal. É a primeira vez que escrevo um artigo no portal do arquiteto e gostaria muito de agradecer ao Samuel por essa abertura. Eu irei compartilhar com vocês uma experiência que tive trabalhando aqui no nosso projeto tentando implementar um comportamento de “onchange” em um componente selectOneMenu do JSF. 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:


    /listagemCarros.xhtml
    
        listarCarros
        /listagemCarros.xhtml
    

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 (http://www.jboss.org/file-access/default/members/jbossajax4jsf/freezone/docs/tlddoc/index.html) 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!

5 Comentários »

  1. Kleber Cardoso 30 de dezembro de 2009 de 10:43 am - Reply

    Olá Eduardo, td bem?
    Quero te parabenizar pelo artigo. Realmente a maioria dos desenvolvedores passam por essa dificuldade, principalmente os que estão iniciando em JSF (EU).
    Gostaria de saber se tem como vc disponibilizar um modelo ou exemplo mais completo referente a esse artigo.

    Agradeço desde já e desejo um Feliz ano novo!!!

    • Eduardo Negrão 20 de janeiro de 2010 de 8:48 am - Reply

      Olá Kleber, tudo ótimo e você? Obrigado pelos parabéns. Você tem razão, para um desenvolvedor iniciante em JSF são inúmeras as dificuldades, pois esta tecnologia se apresenta como uma mudança de paradigma de programação ao desenvolvedor.

      Lhe enviarei um exemplo mais completo por e-mail. Ok?

      Um grande abraço e um feliz ano novo para você também!

      .

  2. Fabiano 2 de dezembro de 2010 de 8:13 am - Reply

    Obrigado, estava a mais de uma semana procurando por uma solução para isso e agora com a ajuda do deste post do Eduardo, foi como um passe de mágica. Pô, nem sei como agradecer!

  3. Eduardo Negrão 12 de dezembro de 2010 de 9:24 pm - Reply

    Fico muito feliz em ter te ajudado Fabiano. Obrigado pelo seu retorno! 😉

  4. João 28 de agosto de 2013 de 6:17 pm - Reply

    Boa tarde Eduardo, gostaria de um exemplo onde um select tenha a marca e ou outro o modelo e o modelo se atualizasse de acordo com a marca que escolhi, poderia me mandar por email?
    Boa tarde, tudo de bom!

Deixe uma resposta »