selectOneMenu dependente em JSF

Aproveitando este Tópico que fala de SelectOneMenu Dependentes, vou tentar explicar meu problema atual.

Consegui fazer com que ao selecionar uma opção no primeiro SelectOneMenu o segundo seja carregado com as informações pertinentes a escolha do primeiro. Quando eu escolho pela primeira vez a opção no primeiro SelectOneMenu, a escolha seguinte não funciona como esperado e assim começa um ciclo de alternâncias de funcionamento e não-funcionamento do elemento.

Veja o vídeo em anexo (Flash), creio que com ele dê para entender bem o problema na prática. Prestem atenção nos valores que aparecem em Contrato e o logo abaixo do botão Cadastrar. O primeiro é setado na primeira linha do método getTodosSistemas e o segundo no final da página, ambos listados abaixo.

Alguem pode me esclarecer o erro que estou cometendo?

Obrigado!

:arrow: Anexos

Código da Página

[code].
.
.
<h:selectOneMenu id=“regional” value="#{ConsumidorBean.idRegional}" onchange=“submit()” immediate=“false”>
<f:selectItems value="#{RegionalBean.todosParaComboBox}" />
</h:selectOneMenu>

<h:selectOneMenu id=“sistema” value="#{ConsumidorBean.consumidor.sistema.id}">
<f:selectItems value="#{ConsumidorBean.todosSistemas}" />
</h:selectOneMenu>
.
.
.
<h:outputText value="#{ConsumidorBean.idRegional}" />[/code]

Código do Bean

[code]public class ConsumidorBean {

private Consumidor consumidor = new Consumidor();
private GerenciadorConsumidor gerenciador;
private int idRegional;
private DataModel model;
private String mensagem;

public ConsumidorBean() throws Exception{
    gerenciador = new GerenciadorConsumidor();
    consumidor.setCentroCusto(new CentroCusto());
    consumidor.setTipoConsumidor(new TipoConsumidor());
    consumidor.setSistema(new Sistema());
}

.
.
.
public List getTodosSistemas() throws Exception{
consumidor.setNumContrato(Integer.toString(idRegional));
List sistemasJsf = new ArrayList();
List<Sistema> sistemas = new GerenciadorSistema().retornarSistema(idRegional);
for (Sistema elem : sistemas) {
String id = Integer.toString(elem.getId());
sistemasJsf.add(new SelectItem(id, elem.getDescricao()));
}
return sistemasJsf;
}
.
.
.
}[/code]

Aleluia consegui fazer o que queria. Segue uma breve explicação de como fiz para ter meus SelectOneMenu dependetes.

Eu tenho a página JSP com o seguinte código.

[code]<h:selectOneMenu id=“regional” valueChangeListener="#{ConsumidorBean.regionalChanged}" onchange=“submit()”>
<f:selectItems value="#{RegionalBean.todosParaComboBox}" />
</h:selectOneMenu>

<h:selectOneMenu id=“sistema” value="#{ConsumidorBean.consumidor.sistema.id}">
<f:selectItems value="#{ConsumidorBean.todosSistemas}" />
</h:selectOneMenu>[/code]

No atributo valueChangeListener da Tag SelectOneMenu eu vinculei o método regionalChanged do meu Bean Consumidor. Isso quer dizer que este método vai ser chamado sempre que o SelectOneMenu tiver o seu valor modificado.

No atributo onchange eu coloquei a instrução submit() para que o formulário seja enviado e ele seja reprocessado. Acho que esta parte é bem clara para todos.

Agora vamos para o Bean

public void regionalChanged(ValueChangeEvent event){ idRegional = Integer.parseInt((String) event.getNewValue()); }

A assinatura deste método deve ser como está acima: do tipo void e com um parâmetro do tipo ValueChangeEvent. O método getNewValue() retorna um Object ai você tem que fazer os casts como precisar. No meu caso eu preciso de um Inteiro.

:?: Mas porque você não colocou diretamente o cast para Inteiro: idRegional = (Integer) event.getNewValue() :?:

Pelos meus testes eu entendi que mesmo o retorno do método getNewValue() sendo um Object, verdadeiramente o valor é do tipo String. Então eu precisei fazer como fiz. Na verdade eu percebi isso com a mensagem de erro quando tentei usar apenas o cast pra Integer, não sei explicar perfeitamente este detalhe. Se alguém que tenha conhecimento puder contribuir, será de grande valia para todos.

Bem, está ai o mínimo que se precisa para capturar o valor de um SelectOneMenu para popular outro dependente deste.

Para deixar mais claro o funcionamento vou postar o código do método que popula o SelectOneMenu de id sistema.

public List getTodosSistemas() throws Exception{ List sistemasJsf = new ArrayList(); List&lt;Sistema&gt; sistemas = new GerenciadorSistema().retornarSistema(idRegional); for (Sistema elem : sistemas) { String id = Integer.toString(elem.getId()); sistemasJsf.add(new SelectItem(id, elem.getDescricao())); } return sistemasJsf; }

Neste método getTodosSistemas faço uso da propriedade idRegional na terceira linha, cuja recebeu o valor do SelectOneMenu que disparou o método regionalChanged.

Acho que é isso. Nada de avançado demais, mas funcional e tudo isso foi dito, não de forma detalhada, na primeira página deste tópico pelo schmidt.
Comentários são bem vindos, principalmente aqueles que mencionarem cuidados, alertas e possíveis problemas com essa implementação.

Obrigado!

Bem,

Ainda não me livrei dos benditos SelectOneMenu. Estou com um problema quando tento salvar o formulário. Nele eu tenho um SelectOneMenu chamado sistema, que é dependente do SelectOneMenu chamado regional.

Quando eu tento salvar o form recebo a mensagem Erro de validação “sistema”: O valor não é uma opção válida. E neste mesmo momento percebo que o SelectOneMenu sistema não ficou populado como deveria.

Coloquei um vídeo em anexo para esclarecer mais a situação.
Será que alguém sabe como me ajudar?

Dá uma olhada aqui, isso pode te ajudar,
http://www.rponte.com.br/2008/02/01/selectonemenu-converter-erro-de-validacao/

Abraços e boa sorte.

Cara,

Eu acho que o meu problema não é o mesmo do link que tu passou.

A grosso modo, meu problema é que quando eu submeto o form com o SelectOneMenu sistema tendo uma das opções selecionadas, este objeto não lista novamente todos os itens de acordo com a opção de Regional selecionada.

A princípio eu achei que ia funcionar já que tenho o método getTodosSistemas (Bean em anexo).