JSF, RichFaces, AJAX e combobox alinhados
Em meus estudos sobre JSF e AJAX, gostei muito do pacote disponibilizado pela JBoss, o RichFaces. A intensão é usar o mais puro do JSF porém, aproveitando o que cada componente oferece de melhor.
O RichFaces é interessante e muito completo, oferece diversos recursos para web que até então o HTML estava limitado, como o combobox (leia-se também dropdown) com área aberta para localização de textos – <rich:comboBox/>. Ao contrário deste alguns outros componentes apresentam problemas sérios de incompatibilidade com o Apache MyFaces (Tomahawk), por exemplo, o <rich:fileUpload/>.
Estudando esses componentes observei suas vantagens e falhas, decidi então criar este exemplo de um recurso tão comum em formulários e simples com JSF, que são os combobox dependentes ou alinhados.
Vamos continuar com o esquema de Países e Estados, um combobox para cada, sendo que ao modificar o Pais através do AJAX os estados relacionados serão carregados.
A configuração básica do Faces e RichFaces no web.xml será ocultada, porém você poderá fazer o download do projeto no fim deste post.
O projeto está estruturado da seguinte maneira:
No Manager Bean destacam-se os métodos getPaises() e actionCarregarEstados(), o primeiro retorna um array de itens – SelectItem[] – tipo de dado complexo que será tratado pelo componente JSF, já o actionCarregarEstados() é responsável por carregar os estados relacionados ao pais.
public class UirapuruManagerBean {
private Pessoa pessoa = new Pessoa();
private SelectItem[] estados;
/* getters e setters ocultados */
/* carrega os paises */
public SelectItem[] getPaises(){
List<pais> lp = regiaoDao.getAllPais();
List<selectItem> itens = new ArrayList<selectItem>(lp.size());
for( Pais p : lp ){
itens.add( new SelectItem(p.getId_pais(), p.getNm_pais()) );
}// for end
return itens.toArray( new SelectItem[itens.size()] );
}
/* carrega os estados */
public SelectItem[] getEstadosByPais(int id_pais){
List<estado> estados = regiaoDao.getEstadosDoPais(id_pais);
List<selectItem> itens = new ArrayList<selectItem>(estados.size());
for( Estado e : estados ){
itens.add( new SelectItem(e.getId_estado(), e.getNm_estado()) );
}// for end
return itens.toArray( new SelectItem[itens.size()] );
}
/* */
public String actionCarregarEstados(){
this.estados = getEstadosByPais(getPessoa().getPais().getId_pais());
return "SUCCESS";
}
}
Uma observação importante antes de seguirmos: os beans Pessoa, Pais e Estado são simples e foram criados apenas para uma interpretação melhor, é importante e somente assim este exemplo irá funcionar perfeitamente se no bean Pessoa, os atributos pais e estado sejam inicializados. Já que não estamos trabalhando com Spring o Faces não irá fazer este entendimento e uma exceção NullPointerException será lançada, para evitar tal faça isto:
public class Pessoa implements Serializable {
private int id;
private String nome;
// criando os objetos
private Pais pais = new Pais();
private Estado estado = new Estado();
/* getters e setters ocultados */
}
Okay. Feita a observação vamos para a parte final, a montagem do JSP.
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <%@ taglib prefix="a4j" uri="http://richfaces.org/a4j"%>
Não esqueça que qualquer página JSF deve ser elaborada dentro da tag <f:view/> e, que sem a definição do formulário <h:form/> o AJAX não irá funcionar.
<f:view>
<h:form>
<h:panelGrid border="0" columns="2" width="500" cellpadding="1" cellspacing="2">
<h:outputLabel value="Pais" for="pais"/>
<h:selectOneMenu id="pais"
value="#{umb.pessoa.pais.id_pais}"
rendered="true">
<f:selectItems value="#{umb.paises}"/>
<a4j:support event="onchange"
ajaxSingle="true"
action="#{umb.actionCarregarEstados}"
reRender="pais,estado"/>
</h:selectOneMenu>
<h:outputLabel value="Estado" for="estado"/>
<h:selectOneMenu id="estado"
value="#{umb.pessoa.estado.id_estado}"
rendered="true">
<f:selectItems value="#{umb.estados}"/>
</h:selectOneMenu>
</h:panelGrid>
</h:form>
</f:view>
Na tag <h:selectOneMenu/> deve-se colocar na propriedade VALUE o atributo que irá receber o valor selecionado no combobox, outras propriedades excenciais são o ID que identifica o componente e RENDERED que indica a renderização. A tag <f:selectItems/> invoca o método – umb.getPaises() – que contém os itens do combobox.
Até o momento utilizamos apenas JSF puro, o RichFaces é representado na tag <a4j:support/> responsável por identificar quando um evento do tipo OnChange é feito e fazer a ação definida no método umb.actionCarregarEstados, e por fim na propriedade reRender estão separados por vírgulas os componentes que serão renderizados.
Seguindo esta linha de raciocínio você conseguirá fazer vários níveis de dependência facilmente, o componente <rich:combobox/> também permite este tipo de interação, com alguns recursos a mais.
Faça aqui o download do projeto.

Fale cara, tudo bom?!
Achei bem interessante a tua abordagem sobre os combos dependentes, ficou show! :D
Eu segui esse teu tutorial em um sistema que eu to implementando, só que eu tive um problema na hora de armazenar o objeto no banco, tú enfrentou algo do tipo?
Tentei usar a tag pra resolver isso (meu managed bean tem escopo “request”).
Abraços.
Erick Jeronimo
10 set 08 at 18:58
acho que o blog não aceita qualquer coisa similar a um html :P
A tag é a a4j:KeepAlive.
Erick Jeronimo
10 set 08 at 18:59
Luciano,
Muito legal seu exemplo!! Parabéns.
Acontece que no zip do projeto, faltou um jar referenciado na sua TOMCATLIB, chamado UtilTools.jar.
Você poderia me envia-lo?
Agradeço desde já.
Um grande abraço.
Rodrigo Bisterço
6 fev 09 at 20:36
Aonde baixo a aplicação JSF, RichFaces, AJAX e combobox alinhados.
O link para Uirapuru.zip esta quebrado!
Fique na paz!!!
Ivan
20 fev 09 at 14:19
Não estou conseguindo baixar os jars do rich faces, entrei no site do JBOSS baixo o rich faces, só que não encontro os jars, tem várias pastas compactadas só que não encontro os jars em menhuma delas.
Alguém pode me ajudar?
ivan_fit@yahoo.com.br
Ivan
25 fev 09 at 14:43
Estou tentando rodar a aplicação e importa tools.util.ConnManager e tools.util.Util. Acho que é o mesmo do post do Rodrigo.
Além do mais eu também gostaria de armazenar em banco.
A paz!
Ivan
25 fev 09 at 16:20
Pessoal, desculpe pelos links quebrados, foi por conta de uma mudança de servidor.
Abaixo o link para o UtilTool.zip.
http://www.lucianosilva.com/download/UtilTools.zip
Abraços.
Luciano
25 fev 09 at 21:37
Ae, o código tá funcionando muito bem. Certinho.
Adaptei pro meu projeto. Agora é só alegria.
Parabéns pelo post!
Abraços…
Sergio Fantin
11 mar 09 at 14:56
Olá, Luciano.
preciso renderizar um terceiro componente table assim que o primeiro combo for clicado, qual é a idéia?
———————————–
Agradeço antecipadamente!
Sergio Fantin
12 mar 09 at 10:04
Muito bom!
Um dos problemas mais comuns nas aplicações desenvolvidas com JSF e você explanou muito bem sobre o assunto!
Parabéns!
Rafael Ponte
1 abr 09 at 13:22
Oi Luciano!
Consegui fazer o exemplo funcionar, mas na maioria das situações precisamos passar o objeto todo (umb.pessoa.selectedPais) para o MB e não somente o seu ID (umb.pessoa.pais.id_pais). Acredito que esse seja o maior problema em se trabalhar com combos.
Se puder postar um exemplo desse tipo ajudaria muita gente. Tá dada a dica.
:)
Tati
7 abr 09 at 9:21
Muito bom, mas to precisando criar componentes dinamicamente, tipo quando clicar num link aparece um inputtext, sera que vc naum teria um tutorial que faca isso.
Obrigado e parabens
Savio
8 abr 09 at 21:17
Savio, você necessita disso em JSF mesmo?
Não sei qual o cenário que você está trabalhando, mas talvez utilizando um simples JavaScript resolva seu problema.
Se quiser posso tentar ajudar, mande em PVT para (luciano@lucianosilva.com).
Abraço.
Luciano
9 abr 09 at 14:25
Tati, talvez eu não tenha compreendido, mas se você utilizar a classe e não o atributo, irá dar uma exception (exception javax.servlet.ServletException: Value is no String) já que o espera uma String, entendeu?
Em que situação você irá precisar além do ID?
Valeu! =)
Luciano
10 abr 09 at 22:09
Luciano, estou tendo que fazer uma aplicação que utiliza exatamente este exemplo que você mostrou. Porém ao submeter a tela está apresentando a exceção java.util.NoSuchElementException. Quando seleciono uma combo, a segunda é preenchida corretamente, porém ao visualizar o código fonte, a segunda combo está vazia, como se não houvesse nenhum dado na lista.
Estou precisando muito disso!
Diego
12 jun 09 at 15:30
Olá Luciano, td bem??
Gostaria de parabeniza-lo pelo artigo. Achei muito interessante. Gostaria de tirar uma dúvida com vc no que se refere à geração de banco. Estou tentando gerar o banco através de uma classe Gerabanco usando hibernate, porém está dando uma exception. Teria como vc me ajudar?? Agradeço man.
Kleber Cardoso
12 jan 10 at 12:43