JSF 2.0 + onComplete não funciona [RESOLVIDO]

Ae pessoal, estou com problemas ao utilizar o evento onComplete no JSF 2.0. Criei um app simples para demonstrar tal questão. Estou utilizando o componente Primefaces versão 2.0.1, e a tag p:commandButton possui esse evento. Porém o mesmo não se comporta da mesma maneira que o <a4j:support onComplete="" /> existente na versão 1.2 do JSF. O problema é o seguinte. Ao disparar uma action, o evento onComplete recebe uma string do Managed Bean, como no exemplo abaixo, exibindo um alert. Só que nesse caso, o alert não está sendo exibido, apenas se eu colocá-lo diretamente no evento onComplete da tag do p:commandButton. Mas ai nesse caso, o alert é exibido mesmo quando os campos não estão preenchidos, verificado atraves do required dos inputs. Quem puder me ajudar, fica aí o desafio, seguem os códigos abaixo:

Página index.xhtml

&lt;?xml version='1.0' encoding='UTF-8' ?&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.prime.com.tr/ui"
      xmlns:f="http://java.sun.com/jsf/core"&gt;
    &lt;h:head&gt;
        &lt;title&gt;Teste&lt;/title&gt;
    &lt;/h:head&gt;
    &lt;h:body&gt;
        &lt;h:form&gt;
            &lt;p:panel style="margin-top: 200px; margin-left: 500px; width: 300px;"&gt;
                &lt;f:facet name="header"&gt;
                    &lt;h:outputText value="Teste de Soma" /&gt;
                &lt;/f:facet&gt;
                &lt;h:panelGrid id="pgrTotal" columns="2"&gt;
                    &lt;h:outputText id="optValor1" value="Valor 1:" /&gt;
                    &lt;h:inputText id="iptValor1" size="30" maxlength="20" value="#{bean.valor1}"
                                 required="true" requiredMessage="Informe o primeiro valor" /&gt;
                    &lt;h:inputHidden /&gt;
                    &lt;h:message for="iptValor1" styleClass="fonteAlerta" showDetail="true" showSummary="false" /&gt;
                    &lt;h:outputText id="optValor2" value="Valor 2:" /&gt;
                    &lt;h:inputText id="iptValor2" size="30" maxlength="20" value="#{bean.valor2}"
                                 required="true" requiredMessage="Informe o segundo valor" /&gt;
                    &lt;h:inputHidden /&gt;
                    &lt;h:message for="iptValor2" showDetail="true" showSummary="false" /&gt;
                    &lt;h:outputText value="Soma:" /&gt;
                    &lt;h:outputText id="optTotal" value="#{beanController.total}" /&gt;
                &lt;/h:panelGrid&gt;
                &lt;f:facet name="footer"&gt;
                    &lt;p:commandButton id="btnSomar" value="Somar" action="#{beanController.realizaSoma}" 
                                     update="pgrTotal" oncomplete="#{beanController.mensagem}" /&gt;
                    &lt;h:outputText value="&#160;" /&gt;
                    &lt;h:commandButton value="Limpar" immediate="true" type="reset" /&gt;
                &lt;/f:facet&gt;
            &lt;/p:panel&gt;
        &lt;/h:form&gt;
    &lt;/h:body&gt;
&lt;/html&gt;

Bean:



import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

/**
 *
 * @author Lessandro
 */
@ManagedBean(name = "bean")
@RequestScoped
public class Bean {

    private double valor1, valor2;

    public double getValor1() {
        return valor1;
    }

    public void setValor1(double valor1) {
        this.valor1 = valor1;
    }

    public double getValor2() {
        return valor2;
    }

    public void setValor2(double valor2) {
        this.valor2 = valor2;
    }
}

Managed Bean:



import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

/**
 *
 * @author Lessandro
 */
@ManagedBean(name = "beanController")
@SessionScoped
public class BeanController {

    private double total;
    private String mensagem;

    public void realizaSoma() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Bean bean = (Bean) facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(),
                null, "bean");
        total = bean.getValor1() + bean.getValor2();
        setMensagem("alert('Done');");
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public String getMensagem() {
        return mensagem;
    }

    public void setMensagem(String mensagem) {
        this.mensagem = mensagem;
    }
}

Agradeço desde já pela atenção,
Att,
Lessandro

Lessandro, não entendi bem o que tu quer fazer no oncomplete, tu quer mostrar um alert dizendo que o calculo foi ok e apenas exibir os h:messages caso der erro? eu acho que seria melhor tu validar do lado do servidor e caso os argumentos não estivem ok tu adciona um facesMessage do tipo ERROR e se tudo estiver ok adiciona uma facesMessages do tipo INFO, depois no update do botão é só tu atualizar um p:messages ou p:notificatioBar. Mas se tu insistir nessa solução (que não entendi bem o que tu quer) acho que tá pra usar CallbackParams do primefaces , da uma olhada nesse tópico: http://primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=1901&start=10

espero ter ajudado, abraços.

Eh, isso foi apenas uma versão de teste. No meu caso eu utilizo o evento onComplete retornando uma string que exibe um modal quando ocorre algum erro ou quando um registro é inserido com sucesso, algo como dlg.show();
Vou dar uma olhada em q vc falou, mas fica ai o motivo da utilização.
Abs,
Lessandro

ve se te ajuda Lessandro:

index.xhtml

    
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
     <html xmlns="http://www.w3.org/1999/xhtml"
           xmlns:h="http://java.sun.com/jsf/html"
           xmlns:p="http://primefaces.prime.com.tr/ui"
           xmlns:f="http://java.sun.com/jsf/core">
        <h:head>
            <title>Teste</title>
        </h:head>
       <h:body>
            <h:form>
               <p:panel>
                   <f:facet name="header">
                       <h:outputText value="Teste de Soma" />
                  </f:facet>
                  <h:panelGrid id="pgrTotal" columns="2">
                       <h:outputText id="optValor1" value="Valor 1:" />
                      <h:inputText id="iptValor1" size="30" maxlength="20" value="#{bean.valor1}"
                                    required="true" requiredMessage="Informe o primeiro valor" />
                       <h:inputHidden />
                      <h:message for="iptValor1" styleClass="fonteAlerta" showDetail="true" showSummary="false" />
                       <h:outputText id="optValor2" value="Valor 2:" />
                       <h:inputText id="iptValor2" size="30" maxlength="20" value="#{bean.valor2}"
                                   required="true" requiredMessage="Informe o segundo valor" />
                      <h:inputHidden />
                      <h:message for="iptValor2" showDetail="true" showSummary="false" />
                      <h:outputText value="Soma:" />
                     <h:outputText id="optTotal" value="#{beanController.total}" />
                  </h:panelGrid>
                  <f:facet name="footer">
                      <p:commandButton id="btnSomar" value="Somar" action="#{beanController.realizaSoma}"
                                        update="pgrTotal" oncomplete="handleComplete(args)" />
                        <h:outputText value=" " />
                        <h:commandButton  value="Limpar" immediate="true" type="reset" />
                    </f:facet>
              </p:panel>

           </h:form>
                <p:dialog widgetVar="dlg" fixedCenter="true" modal="true" effect="slide">
                    <p:panel header="INFORMATION">
                        <h2>#{beanController.mensagem} </h2>
                       </p:panel>
                </p:dialog>
           <script type="text/javascript">
               function handleComplete(args){
                   //alert(args.error);
                   if(! args.error){
                       dlg.show();
                   }
                   
                
              }

              
           </script>
     </h:body>
    </html>

BeanController

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package teste;

/**
 *
 * @author rmpestano
 */
import javax.faces.application.FacesMessage;
     import javax.faces.bean.ManagedBean;
     import javax.faces.bean.SessionScoped;
     import javax.faces.context.FacesContext;
import org.primefaces.context.RequestContext;

    @ManagedBean(name = "beanController")
    @SessionScoped
   public class BeanController {

        private double total;
        private String mensagem;

        public void realizaSoma() {
            FacesContext facesContext = FacesContext.getCurrentInstance();

            Bean bean = (Bean) facesContext.getApplication().getELResolver().getValue(facesContext.getELContext(),
                    null, "bean");
            
            validate();
            total = bean.getValor1() + bean.getValor2();
        }

        public void validate(){
            RequestContext context = RequestContext.getCurrentInstance();

            if(true){//aqui incluia sua logica de negocio
              context.addCallbackParam("error", false);
              this.mensagem = "MENSAGEM";
            }
            else{
              context.addCallbackParam("error", true);
            }
        }

       public double getTotal() {
            return total;
        }

        public void setTotal(double total) {
            this.total = total;
        }

        public String getMensagem() {
            return mensagem;
       }

       public void setMensagem(String mensagem) {
            this.mensagem = mensagem;
       }
    }

O context ali aceita um objeto tambem, outra maneira é trabalhar com o atributo rendered do dialog enfim espero que tenha ajudado. abraços.

Hum, ok amigo Rafael.
Estarei fazendo as devidas alterações e o mais breve possível estarei postando a questão.
Agradeço desde já pela sua atenção em ajudar.
É assim que conseguiremos cada vez mais disseminar o conhecimento e contribuir com problemas de muitas outras pessoas.
Um gde abraço,
Att,
Lessandro

:thumbup:

não sei se você chegou a olhar o tópico que te passei mas depois que postei ele vi que foi adicionado um callbackParam que resolve justamente o seu caso, que é o “args.validationFailed” que vai ser true quando o usuário não preencher um campo required por exemplo, voce pode ver no exemplo abaixo. Abraços.

http://www.primefaces.org:8080/prime-showcase/ui/callbackParams.jsf

Sim sim, vc havia me indicado esse link no outro post.
Tentei fazê-lo aqui, mas por algum motivo, não funcionou.
La no site é utilizado um método com actionListener, porém utilizando o p:commandButton e no onComplete
chamando o evento javascript o mesmo nem entra no método :confused:
Vou adaptar meu código com as alterações q vc me indicou, e ver se vai funcionar.
Assim que tiver uma resposta, posto aki.
Abs,
Lessandro

Fala Rafael, blz?
Como vc havia me dito, refiz o código aqui, e alterei algumas coisas tb…
A ideia continua a mesma, mas com algumas modificações para o meu caso específico. Segue abaixo:

Método salvar no ManagedBean UsuarioController.java responsável por incluir o usuário na base, fica assim:


    public void salvar(ActionEvent actionEvent) {
        try {
            getUsuarioDAO().salva(usuario);
            setMensagem(ResourceBundle.getBundle("/message").getString("usuario.criadoSucesso"));
        } catch (Exception e) {
            setMensagem(e + " " + ResourceBundle.getBundle("/message").getString("usuario.erroIncluir"));
        }
    }

O grande detalhe nesse código acima, é a necessidade da utilização de um ActionEvent responsável por comunicar-se com a página web,
onde esta consegue interpretar que o evento foi realizado.

A página incluirUsuario.xhtml fica assim:

Script que interpreta se o required foi realizado. Caso os campos required tenham sido todos preenchidos, ele executa o script, chamando o dialog: <p:dialog> conforme necessidade do desenvolvedor.

            &lt;script type="text/javascript"&gt;
                function retornaEvento(args) {
                    if(!args.validationFailed) {
                        dlg.show();
                    }
                }
            &lt;/script&gt;

Aqui a mensagem que é exibida dentro do dialog, a atualizada posteriormente pela tag update="":


&lt;p:dialog id="dialog" header="#{msg['modalPanel.msgAlerta']}" widgetVar="dlg"
    height="120px;" width="300px;" effect="FADE" fixedCenter="true" resizable="false"&gt;
    &lt;h:panelGrid columns="1" cellspacing="5px;"&gt;
         h:outputLabel id=&quot;oplMensagem&quot; value=&quot;#{usuarioController.mensagem}&quot; styleClass=&quot;fonteAlerta&quot; /&gt;
         h:commandButton id=&quot;cbtOk&quot; value=&quot;#{msg['botao.ok']}&quot; styleClass=&quot;botoes&quot; action=&quot;#{usuarioController.preparaLista}&quot; immediate=&quot;true&quot; /&gt;
    &lt;/h:panelGrid&gt;
&lt;/p:dialog&gt;

Abaixo o botão que dispara o javascript. Observem o evento onComplete chamando a função JavaScript e um actionListener chamando o método
salvar do UsuarioController.java, e o update atualizando o painelGrid de Usuario para mostrar os campos que são obrigatórios, pois coloquei um
h:message para cada campo, e upgrade também para o outputLabel para a mensagem que exibo dentro do p:dialog.


&lt;p:commandButton id="cbtIncluir" value="#{msg['botao.incluir']}" styleClass="botoes" actionListener="#{usuarioController.salvar}"
     oncomplete="retornaEvento(args)" update="pgrUsuario, oplMensagem"&gt;

Abraços a todos,
Quem estiver com dificuldades fica o exemplo aí.
Agradeço desde já ao Rafael pela ajuda, pois é assim que vamos disserminando nossos conhecimentos,
Att,
Lessandro

Lessandro conseguiu ?

Sim, funcionou perfeitamente.
Descobri uma outra alternativa tb, deixando o rendered do dialog atribuído à um atributo no MB.
Quando a inclusao ocorrer com sucesso, setamos o atributo para true, e renderizamos o dialog, sem a necessidade de dar o show.
Abs,
Lessandro

Olá Lessandro.

como vc faz para abrir o Dialog sem show?

Grato
Ademir

Dê uma olhada no meu blog:


Abs,
Lessandro