Primefaces: validar form dentro de um p:dialog [RESOLVIDO]

Olá Pessoal,

Estou testando/estudando o Primefaces e JSF2.0 antes eu usava o JSF 1.2 com MyFaces Tomahawk, montei
meu ambiente no eclipse Helios, Jboss Tools, Jboss 6, EJB3 e ja coloquei o Primefaces 3.0, mas a duvida q estou
acho que independe do ambiente, vamus lá

montei um formulario dentro dele um p:tree e um commandbutto para acionar um p:dialog onde eu posso
editar o registro selecionado no TREE ou até mesmo incluir novos registros, até ai tudo blz, o problema
é que por exemplo se o usuário deixar de preencher algum campo obrigatório no form dentro do dialogo
é mostrado a msg de campo requerido, mas o dialogo é fechado mesmo assim e na verdade eu gostaria
de manter o dialogo aberto até que o registro seja salvo corretamente ou o usuário cancele a edição.

segue o código fonte da minha página xhtml:

		<p:growl id="growl" showDetail="true" sticky="false" life="10000"/>  
		<h:form id="frmNode">
			<h:panelGrid columns="1" id="pnePlanoContas" styleClass="center">
				<p:tree 
					id="treePlanoContas" 
					value="#{mbCadCtaCtb.planoDeContas}" 
					var="node"
		            selectionMode="single"
		            update="frmCadCtb:pneFormCadCtb growl"
		            expandAnim="FADE_IN" collapseAnim="FADE_OUT"
		            selection="#{mbCadCtaCtb.selectedNode}"
		            nodeSelectListener="#{mbCadCtaCtb.aoSelecionarConta}">  
			        <p:treeNode 
			            type="mae" 
			        	expandedIcon="ui-icon ui-icon-folder-open"
	                    collapsedIcon="ui-icon ui-icon-folder-collapsed">
			            <h:outputText value="#{node.codigo} - #{node.nome}" />
			        </p:treeNode>
			        <p:treeNode type="filha" icon="ui-icon ui-icon-document">  
            			<h:outputText value="#{node.codigo} - #{node.nome}" styleClass="documentStyle"/>  
        			</p:treeNode> 
		    	</p:tree>
		    	<f:facet name="footer">
					<p:commandButton 
                                               value="Editar"    image="ui-icon-pencil" update="growl" 
                                               ajax="true" actionListener="#{mbCadCtaCtb.editarConta}" 
                                               onsuccess="dlgEditConta.show()" />
					<p:commandButton value="Novo" image="ui-icon-circle-plus" 
                                                update="frmCadCtb:pneFormCadCtb growl" ajax="true" 
                                                actionListener="#{mbCadCtaCtb.novaContaContabilAjax}" 
                                                onsuccess="dlgEditConta.show()" />
					<p:commandButton
						id="cmdExcluir" 
						value="Excluir" 
						image="ui-icon-trash"
						update="frmNode:pnePlanoContas growl"
						actionListener="#{mbCadCtaCtb.excluirConta}" />
		    	</f:facet>
	    	</h:panelGrid>
    	</h:form>
		<p:dialog header="Conta Contábil" widgetVar="dlgEditConta"  height="180" width="400" showEffect="explode" hideEffect="explode" >  
			<h:form id="frmCadCtb">
				<h:panelGrid columns="3" id="pneFormCadCtb">
					<h:outputText value="Conta Superior: " />  
			        <h:selectOneMenu 
			        	value="#{mbCadCtaCtb.contaEmEdicao.contaSuperior.id}"
			           	id="cboContaSuperior"
			           	effect="drop"
			           	required="true" 
			           	requiredMessage="Conta Superior deve ser Informada">  
						<f:selectItem itemValue="" itemLabel="Selecione..." />
			            <f:selectItems value="#{mbCadCtaCtb.listContasSup}"/>
			        </h:selectOneMenu>
				    <h:message for="cboContaSuperior" showDetail="false"/>
					<h:outputText value="Codigo:" />
					<h:inputText id="txtCodCta"  value="#{mbCadCtaCtb.contaEmEdicao.codigo}" required="true" requiredMessage="Codigo da conta deve ser informado" />
			        <h:message for="txtCodCta" showDetail="false"/>
					<h:outputText value="Nome:" />
					<h:inputText id="txtNomCta" value="#{mbCadCtaCtb.contaEmEdicao.nome}" size="50" required="true" requiredMessage="Nome da conta deve ser informado" />
			        <h:message for="txtNomCta" showDetail="false"/>
					<h:outputText value="Tipo de Lançamento Aceitos: " />  
			        <h:selectOneMenu 
			        	value="#{mbCadCtaCtb.contaEmEdicao.tipoLancamento}"
			           	id="cboTipoLancamento"
			           	required="true" 
			           	requiredMessage="Tipo de Lançamento deve ser Informado">  
						<f:selectItem itemValue="A" itemLabel="Ambos" itemDescription="Aceita lançamentos a débito e a crédito" />
						<f:selectItem itemValue="D" itemLabel="Lançamentos a Débito" />
						<f:selectItem itemValue="A" itemLabel="Lançamentos a Crédito" />
						<f:selectItem itemValue="A" itemLabel="Não Aceita Lançamentos" />
			        </h:selectOneMenu>
					<h:outputText value="Histórico Padrão Débito:" />
					<h:inputText id="txtHisPdrDeb" value="#{mbCadCtaCtb.contaEmEdicao.historicoDebito}" size="50" required="false" />
			        <h:message for="txtHisPdrDeb" showDetail="false"/>
					<h:outputText value="Histórico Padrão Crédito:" />
					<h:inputText id="txtHisPdrCre" value="#{mbCadCtaCtb.contaEmEdicao.historicoCredito}" size="50" required="false" />
			        <h:message for="txtHisPdrCre" showDetail="false"/>
			        <f:facet name="footer">
						<p:commandButton 
							id="cmdSalvar"
							value="Salvar" 
							image="ui-icon ui-icon-circle-check"
							update="frmNode:pnePlanoContas growl"
							actionListener="#{mbCadCtaCtb.salvarConta}" />
						<p:commandButton
							id="cmdReset" 
							image="ui-icon ui-icon-arrowreturnthick-1-w" type="reset" value="Limpar Campos" ajax="false"/>
						<p:commandButton image="ui-icon ui-icon-circle-close" action="formListContaContabil" ajax="false" immediate="true"/>
			        </f:facet>
	        	</h:panelGrid>
	        </h:form>
		</p:dialog> 

segue tb um trecho do managedbean, mais especificamente o metodo acionado pelo botao salvar (mbCadCtaCtb.salvarConta) que salva o registro

@SessionScoped
@ManagedBean(name="mbCadCtaCtb")
public class MBCadCtaCtb implements Serializable
{
	@EJB
	private Contab				beanContab;
        private ContaContabil 		contaEmEdicao = new ContaContabil();

     (...)

    public void salvarConta(ActionEvent ae) throws Exception
    {
    	FacesContext context = FacesContext.getCurrentInstance();
    	
    	try
	{
    		beanContab.salvarContaContabil(contaEmEdicao);
    		contaEmEdicao = null;
    		atualizar=true;
    		context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Registro Salvo com sucesso.",""));  
	}
	catch (Exception e)
	{
    		context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Falha ao Salvar Registro.",e.getMessage()));  
    		throw e;
	}
    }

    public void editarConta(ActionEvent eve)
    {
    	FacesContext context = FacesContext.getCurrentInstance();
    	if (this.selectedNode==null)
    	{
    		context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,"Selecione a conta que deseja editar.",""));
    		return;
    	}
    		
    	this.contaEmEdicao= (ContaContabil)(this.selectedNode.getData());
    }


}

é isso se alguem puder ajudar…

[]s

Não sei se você ainda precisa, mas dê uma olhada: http://www.primefaces.org/showcase/ui/dialogLogin.jsf

Pra variar, o showcase tá fora do ar agora. Mas aí tem o que você precisa.

No seu método de gravar você pode mandar um retorno semelhante a isso:

RequestContext requestContext = RequestContext.getCurrentInstance(); requestContext.addCallbackParam("sucesso", true);

Usar JS que pegue esse retorno

function sucesso (xhr, status, args){ if(args.sucesso == true) { dlgEditConta.hide(); } }

E no botão chamar esse JS.

Obrigado Marco e Edu,

o caminho é este mesmo, to tentando implementar as sugestões de vcs,
não consegui ainda, mas assim que avançar posto o retorno.

estava com os mesmos problemas aqui e consegui resolver por esse caminho :slight_smile:

vlws

Oi Carlos que bom que conseguiu,
o meu tb está funcional surgiram outros problemas, como por exemplo não funcionar o dialogo como modal, que vou gerar outro post e este post vou considerar resolvido, pois o propósito do posto foi alcançado

Fiz varias alterações, uma delas foi trocar o p:tree por um datatable mas não por causa de erros, foi mudança de planos mesmo,
em cada linha coloquei os botoes Ver, Alterar e excluir ficou bem parecido com o exemplo do showcase http://www.primefaces.org/showcase-labs/ui/datatableRowSelectionByColumn.jsf

Mas concluindo gostaria de compartilhar algumas dificuldades que tive e fui ajustando, de repente pode ser util:

  1. No inicio eu tinha colocado o código javascript logo abaixo da tag p:dialog, tive que ajustar meu template de forma que esse código
    javascript ficasse dentro da tag header do html, do contrário a função nao ficava acessivel.

  2. Tive que colocar o immediat=true nos botoes que chama o dialog para inclusao, alteração e exclusão, do contrário ele não
    atualizava o objeto(linha da datatable) como se a tag <f:setPropertyActionListener não funcionasse. Estranho q no exemplo do showcase nao tem isso.

  3. E por ultimo tive que trocar uma chamada do jQuery conforma abaixo

  function validaForm(xhr, status, args) 
		    {  
		        if(args.validationFailed || !args.sucesso) 
		        {  
                           // Troquei esta linha
		           // jQuery('#dlgEditReg').parent().effect("shake", { times:3 }, 100); 
			   //Por esta
			  $(PrimeFaces.escapeClientId('frmGenero:dlgEditReg')).parent().effect("shake", { times:5 }, 100);
		        } 
		        else 
		        {  
		        	dlgViewGenero.hide();  
		        }  
		    }  

Obrigados a todos que colaboraram.

Veja se não é por causa do equals e hashCode. Aqui no fórum tem tópicos sobre isso.

Vlw

Olá!
Tome cuidado que as vezes pode não estar funcionando por conta de bugs do PrimeFaces 3.0
Essa versão ainda vai demorar pra ficar pronta, veja se realmente precisa usar ela agora, caso contrário use uma versão estável, por exemplo a 2.2.1

Eu estava tentando resolver um problema semelhante a esse na minha aplicação.
Eu estava usando essa seguinte verificação no dialog:

 visible="#{not empty facesContext.maximumSeverity}"

Ou seja, se existir mensagem de erro enviada pelo teu ManagedBean, o dialog deve permanecer aberto. Porém, comecei a enfrentar problemas quando meu dialog possuía o atributo “modal=true” ou quando eu tinha de dar updates em mais de um componente na tela.

Comecei a trabalhar com a mais nova versão do Primefaces a 2.2.1 e notei que esse problema de manter o dialog aberto em caso de mensagens de erro continua.

A solução proposta funciona, mas será que é válido em um aplicação que faz uso de diversos dialogs de cadastro, ter que definir um JS pra toda verificação, sem falar que todo Managed Bean precisaria setar o RequestContext ?

Funciona sim, mas parece que a aplicação perde grande parte do fator simplicidade e reusabilidade, sem falar quando for necessário dar manutenção em código.

Alguém sabe de alguma solução menos intrusiva pra resolver esse problema?