Olá galera!
Sou novo com JSF + Primefaces.
Estou enfrentando alguns problemas.
Tenho um selectOneMenu. Quando o usuário selecionar algum valor, será disparado um evento ajax.
O código está dessa forma:
<p:selectOneMenu id="combo" value="#{meuBean.estado}"
converter="converterGenerico" filter="true"
filterMatchMode="contains">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{distribuicaoBean.estados}"
var="estado" itemLabel="#{estado.nome}" itemValue="#{estado}" />
<p:ajax event="change"
listener="#{meuBean.actionCarregarCampoDeCidades()}"
update=":form:meuPanelGrid" />
</p:selectOneMenu>
Quando eu disparo a action listener eu consigo carregar o campo de cidades.
Porém os outros campos do formulário perdem seus valores.
Achei uma solução: colocar o atributo “process=’@form ’” no p:ajax.
Dessa forma não perco os valores. Porém ele processa o formulário inteiro e todas as validações.
Todas as validações(como de campo obrigatório) são realizadas e eu não queria nesse momento.
Só quando o usuário clicasse em gravar.
Obrigado pela ajuda!
igor_ks
Dezembro 11, 2013, 1:27pm
#2
Tente colocar immediate=“true” para o componente ajax, se não der, tente colocar no componente selectOneMenu
Coloquei o immediate=“true”, porém continua a mesma coisa.
Ao executar a action, os campos que estão com required=“true” são processados.
E mensagens de altera ao usuário são mostradas!
Já tô ficando doido com este problema!
Cara, qual o scopo do teu managedbean?
Precisa atualizar o form todo mesmo? Pq não atualiza só o componente com o campo de Cidades?
Cara, coloca teu managedBean ai pra ver como está implementado.
@ManagedBean
@ViewScoped
public class CadastroBean implements Serializable {
private static final long serialVersionUID = 1L;
private String endereco;
private Estado estado;
private Cidade cidade;
private List<Cidade> cidades;
public void actionEstado() {
if (getEstado() != null) {
carregarCidades();
} else {
setCidade(null);
setCidades(null);
}
}
private void carregarCidades() {
setCidades(new ArrayList<Cidade>());
for (Cidade cidade : Cidade.values()) {
if (cidade.getEstado().equals(getEstado())) {
getCidades().add(cidade);
}
}
}
public void gravar() {
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "Info",
"Dados gravados com sucesso"));
System.out.println("Endereço: " + getEndereco());
System.out.println("Estado: " + getEstado());
System.out.println("Cidade: " + getCidade());
}
public Estado[] getEstados() {
return Estado.values();
}
public Estado getEstado() {
return estado;
}
public void setEstado(Estado estado) {
this.estado = estado;
}
public Cidade getCidade() {
return cidade;
}
public void setCidade(Cidade cidade) {
this.cidade = cidade;
}
public List<Cidade> getCidades() {
return cidades;
}
public void setCidades(List<Cidade> cidades) {
this.cidades = cidades;
}
public String getEndereco() {
return endereco;
}
public void setEndereco(String endereco) {
this.endereco = endereco;
}
}
public enum Estado {
DF, GO, SP, RJ, MG
}
public enum Cidade {
BRASILIA(Estado.DF, "Brasília"), TAGUATINGA(Estado.DF, "Taguatinga"), CEILANDIA(
Estado.DF, "Ceilândia"), AGUAS_CLARAS(Estado.DF, "Águas Claras"), RIO_DE_JANEIRO(
Estado.RJ, "Rio de Janeiro"), RIO_DAS_OUTRAS(Estado.RJ,
"Rio das Ostras"), ANGRA_DOS_REIS(Estado.RJ, "Angra dos Reis"), SAO_PAULO(
Estado.SP, "São Paulo"), CAMPINAS(Estado.SP, "Campinas"), SANTOS(
Estado.SP, "Santos"), GOIANIA(Estado.GO, "Goiânia"), ANAPOLIS(
Estado.GO, "Anápolis"), URUACU(Estado.GO, "Uruaçu"), PATOS_DE_MINAS(
Estado.MG, "Patos de Minas"), BELO_HORIZONTE(Estado.MG,
"Belo Horizonte"), OURO_PRETO(Estado.MG, "Ouro Preto"), UBERLANDIA(
Estado.MG, "Uberlândia");
private Estado estado;
private String descricao;
Cidade(Estado estado, String descricao) {
this.estado = estado;
this.descricao = descricao;
}
public Estado getEstado() {
return this.estado;
}
public String getDescricao() {
return this.descricao;
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Teste</title>
</h:head>
<h:body>
<h:form id="form">
<p:growl id="messages" showDetail="true" />
<p:panel header="Exemplo">
<h:panelGrid id="meuPanelGrid" columns="2" cellpadding="5">
<h:outputText value="Endereço: " />
<p:inputText value="#{cadastroBean.endereco}" required="true"
label="Endereço" />
<h:outputText value="Estado: " />
<p:selectOneMenu id="combo" value="#{cadastroBean.estado}"
filter="true" filterMatchMode="contains" required="true"
label="Estado">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{cadastroBean.estados}" var="estado"
itemLabel="#{estado}" itemValue="#{estado}" />
<p:ajax event="change" listener="#{cadastroBean.actionEstado}"
update=":form:meuPanelGrid" />
</p:selectOneMenu>
<h:outputText value="Cidade: "
rendered="#{cadastroBean.estado != null}" />
<p:selectOneMenu id="comboCidade" value="#{cadastroBean.cidade}"
filter="true" filterMatchMode="contains" required="true"
label="Cidade" rendered="#{cadastroBean.estado != null}">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{cadastroBean.cidades}" var="cidade"
itemLabel="#{cidade.descricao}" itemValue="#{cidade}" />
</p:selectOneMenu>
<p:commandButton action="#{cadastroBean.gravar}" value="Gravar"
update="messages" />
</h:panelGrid>
</p:panel>
</h:form>
</h:body>
</html>
Iae galera!
Coloquei meu exemplo completo aí!
Valeu pela ajuda!
Tente com @SessionScoped e faça o que eu falei ali em cima.
ErickRAR na funcionalidade que estou trabalhando não é interessante trabalhar com SessionScoped.
O usuário não pode salvar o estado no servidor por mais de uma página.
Mas mesmo assim não funcionou corretamente.
Atualizando apenas os campos que quero que sejam renderizados, eles não são renderizados corretamente.
Exemplo de como fiz agora:
<h:outputText value="Estado: " />
<p:selectOneMenu id="combo" value="#{cadastroBean.estado}"
filter="true" filterMatchMode="contains" required="true"
label="Estado">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{cadastroBean.estados}" var="estado"
itemLabel="#{estado}" itemValue="#{estado}" />
<p:ajax event="change" listener="#{cadastroBean.actionEstado}"
update="labelCidade cidade" />
</p:selectOneMenu>
<h:outputText id="labelCidade" value="Cidade: "
rendered="#{cadastroBean.estado != null}" />
<p:selectOneMenu id="cidade" value="#{cadastroBean.cidade}"
filter="true" filterMatchMode="contains" required="true"
label="Cidade" rendered="#{cadastroBean.estado != null}">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{cadastroBean.cidades}" var="cidade"
itemLabel="#{cidade.descricao}" itemValue="#{cidade}" />
</p:selectOneMenu>
Preciso que além da combo de cidades sejam carregados, somente podem aparecer os campos quando forem carregados.
Por isso, utilizei o rendered="#{cadastroBean.estado != null}".
Atualizando todo o panelGrid resolve a situação de aparecer/ocultar campo.
Porém os outros valores do formulário são resetados.
E validados.
Cara, tenta fazer assim:
<p:selectOneMenu id="combo" value="#{meuBean.estado}"
converter="converterGenerico" filter="true"
filterMatchMode="contains">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{distribuicaoBean.estados}"
var="estado" itemLabel="#{estado.nome}" itemValue="#{estado}" />
<p:ajax event="change"
listener="#{meuBean.actionCarregarCampoDeCidades()}"
update=":form:meuPanelGrid"
process="@this"
partialSubmit="true" />
</p:selectOneMenu>
Posta ai se resolveu.
Não resolveu.
Retomei ao problema que estava tendo.
Até hoje não consegui resolver.
Tente assim:
<h:selectOneMenu id="selectEstado" value="#{cadastroBean.estado}"
valueChangeListener="#{cadastroBean.onChangeEstado}">
<f:selectItem itemValue="" itemLabel="Selecione um estado:" />
<f:selectItems value="#{cadastroBean.estados}" var="estado" itemLabel="#{estado}" itemValue="#{estado}" />
<p:ajax update=":seuForm" />
</h:selectOneMenu>
<h:selectOneMenu id="selectCidade" value="#{cadastroBean.cidade}" >
<f:selectItem itemValue="" itemLabel="Selecione uma cidade:" />
<f:selectItems value="#{cadastroBean.cidades}" var="cidade" itemLabel="#{cidade}" itemValue="#{cidade}" />
</h:selectOneMenu>
E no seu bean:
public void onChangeEstado(ValueChangeEvent e){
estado = (Estado)e.getNewValue();
// ... sua logica para pegar as cidades do Estado selecionado.
É o mesmo código que eu utilizo para atualizar uma div ao invés de um selectOneMenu, com o mesmo escopo inclusive. Não deve mudar em nada.
Esqueci de retornar ao fórum e dar meu feedback.
Consegui resolver há um tempo atrás.
Tudo foi simplificado ao processar somente o próprio componente, ou os componentes dependentes.
Troquei o valor do atributo process da tag p:ajax para o valor “@this ”:
<p:ajax process="@this " update=“selectCidade”/>
Eu não preciso processar todo o form.
Cada valor que for processado será validado. Então o correto não é processar todo o form, só dos campos que preciso que sejam atualizados no meu bean no momento da requisição ajax.
Após essa mudança, a quantidade de informaçoes diminui muito e tudo ficou muito mais rápido.
Obrigado galera pela força!
Deu tudo certo.
[quote=resende_net@hotmail.com]Não resolveu.
Retomei ao problema que estava tendo.
Até hoje não consegui resolver.[/quote]
Primeiro cria essa classe:
public class ComponenteJSFPrimeFacesUtilConverter {
public static HtmlSelectOneMenu converterAjaxBehaviorEventComboBox(AjaxBehaviorEvent event) {
HtmlSelectOneMenu retorno = null;
if (event.getComponent() instanceof HtmlSelectOneMenu) {
retorno = (HtmlSelectOneMenu) event.getComponent();
}
return retorno;
}
public static InputMask converterAjaxBehaviorEventInputmask(AjaxBehaviorEvent event) {
InputMask retorno = null;
if (event.getComponent() instanceof InputMask) {
retorno = (InputMask) event.getComponent();
}
return retorno;
}
public static SelectOneRadio converterAjaxBehaviorEventSelectOneRadio(AjaxBehaviorEvent event) {
SelectOneRadio retorno = null;
if (event.getComponent() instanceof SelectOneRadio) {
retorno = (SelectOneRadio) event.getComponent();
}
return retorno;
}
public static SelectManyCheckbox converterAjaxBehaviorEventCheckBox(AjaxBehaviorEvent event) {
SelectManyCheckbox retorno = null;
if (event.getComponent() instanceof SelectManyCheckbox) {
retorno = (SelectManyCheckbox) event.getComponent();
}
return retorno;
}
}
No seu controller:
SelectManyCheckbox cb = ComponenteJSFPrimeFacesUtilConverter.converterAjaxBehaviorEventCheckBox(event);
System.out.println(cb.getSubmittedValue());
String[] value = new String[0];
value = (String[]) cb.getSubmittedValue();
if (value.length > 0 && Integer.valueOf(value[0]) > 0) {
exibirPainelComboTreinador = true;
}else {
exibirPainelComboTreinador = false;
}
no teu xhtml:
<h:panelGrid columns=“2” style=“margin-bottom:10px” cellpadding=“5”>#{adminBC.exibirPainelComboTreinador}
<p:selectManyCheckbox id=“perfils” value="#{adminBC.perfilSelecionados}">
<f:selectItems value="#{treinadorBC.listaPerfils}" var=“perfil” itemValue="#{perfil.numero}" itemLabel="#{perfil.nome}"/>
<p:ajax listener="#{adminBC.exibirPainelTreinador}" event=“change” update="@form :painelTreinador" immediate=“true”/>
</p:selectManyCheckbox>
</h:panelGrid>#{adminBC.exibirPainelComboTreinador}
<h:panelGroup rendered="#{adminBC.exibirPainelComboTreinador}" id=“painelTreinador”>
<h:outputLabel value=“Treinador: " />
<p:selectOneMenu id=“treinador” value=”#{adminBC.idTreinadorSelecionado}" label=“Treinadores”>
<f:selectItem itemLabel=“Selecione” noSelectionOption=“true” />
<f:selectItems var=“var” itemLabel="#{var.pessoa.nome}“
itemValue=”#{var.id }" value="#{adminBC.listaTreinador}" />
</p:selectOneMenu>
</h:panelGroup>
</h:panelGroup>
Isso ai vai resolver seu problema.
Abraço
Boa tarde amigos!
passei pelo mesmo problema, tinha uma tela com dois comboList do tipo selectOneMenu, onde um "gatilhava" o outro, porém após processar o gatilho também eram processadas a validações de campo e antes que eu pudesse preencher o próximo campo já exibia a mensagem de validação de campo informando que o mesmo(que não preenchi, somente recarreguei as opções no combo) era obrigatório.
Isso esta intimamente ligado ao ciclo de vida da aplicação JSF. Onde temos:
REQUEST > Aplicar valores do Request > Processar Eventos > Processa Validações > Processa Eventos de mudança de valor > Atualiza Valores do modelo > Processa eventos de ação > Invocar Aplicação > Processa Eventos > Renderiza resposta > RESPONSE.
Uma saída que encontrei foi interromper o ciclo, após o processamento do meu evento, já renderizando os componentes em página sem dar continuidade no ciclo(o que evita a validação do campo). Ficaria +/- assim:
public void actionEstado() {
if (getEstado() != null) {
carregarCidades();
FacesContext.getCurrentInstance().renderResponse();
} else {
setCidade(null);
setCidades(null);
FacesContext.getCurrentInstance().renderResponse();
}
}
A ideia é você usar este recurso "FacesContext.getCurrentInstance().renderResponse();", com base no import javax.faces.context.FacesContext, é renderizar os componentes no seu método que é executado pelo listener, que no seu caso é o cadastroBean.actionEstado()
Testa ai e me fala se resolveu…
Abraços!