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.

compartilhe: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • bodytext
  • Sphinn
  • Facebook
  • TwitThis
  • Slashdot
  • Google
  • Spurl
  • Rec6

2 Responses to “JSF, RichFaces, AJAX e combobox alinhados”


  1. 1 Erick JeronimoNo Gravatar

    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.

  2. 2 Erick JeronimoNo Gravatar

    acho que o blog não aceita qualquer coisa similar a um html :P

    A tag é a a4j:KeepAlive.

Leave a Reply