[RESOLVIDO] Primefaces - desabilitar e renomear p:commandbutton após clicado

Pessoal,

Não consegui com javascript, tampouco com binding. Seguinte:

Ao pressionar o p:commandButton abaixo, ele deve ser renomeado para “pesquisando” e ficar desabilitado enquanto não retornar o resultado do método chamado no action.

Pesquisei pra caramba e nada. Se alguém tiver um simples exemplo mostrando que é possível no Primefaces realizar isto, agradeço muito poder disponibilizá-lo.

<p:commandButton id="btnPesquisa" value="#{pedidoVendaBean.btnPesquisa.value}" action="#{pedidoVendaBean.carregaListaClientes()}" update="clientes" binding="# {pedidoVendaBean.btnPesquisa}"/>

<p:commandButton id="btnPesquisa" value="#{pedidoVendaBean.btnPesquisa.value}" action="#{pedidoVendaBean.carregaListaClientes()}" update="btnPesquisa, clientes" binding="#{pedidoVendaBean.btnPesquisa}"/>
<p:commandButton id="btnPesquisa" value="#{pedidoVendaBean.btnPesquisa.value}" action="#{pedidoVendaBean.carregaListaClientes()}" update="btnPesquisa clientes" binding="#{pedidoVendaBean.btnPesquisa}"/>

No método está assim (escopo SessionScoped no managed bean):

@Named(value = "pedidoVendaBean")
@SessionScoped
public class PedidoVendaBean implements Serializable {
...
    private CommandButton btnPesquisa = new CommandButton();

    public CommandButton getBtnPesquisa() {
        return btnPesquisa;
    }

    public void setBtnPesquisa(CommandButton btnPesquisa) {
        this.btnPesquisa = btnPesquisa;
    }
...
    public PedidoVendaBean() {
        this.btnPesquisa.setDisabled(false);
        this.btnPesquisa.setValue("Pesquisar");
    }
...
    public void carregaListaClientes() {
        this.btnPesquisa.setValue("Pesquisando...");
        this.btnPesquisa.setDisabled(true);
        this.btnPesquisa.setUpdate("clientes");
        System.out.println("oi aqui");

        this.clientela = this.pedido.getCliente().listagemClientes("N", this.pedido.getCliente().getNome_cliente(), "", "", "");
        this.mediumClienteCgc = new ClienteDataCgc(this.clientela);

        this.btnPesquisa.setDisabled(false);
        this.btnPesquisa.setValue("Pesquisar");
    }
...

Já tentou usar ajax?

<p:ajaxStatus onstart="metodoJs();"
			onsuccess="metodoJs();" />

kcobainnn,

Com a tag p:ajaxStatus não.

Você tem um exemplo de um p:commandbutton com p:ajaxStatus ?

Então, eu testei aqui e percebi uma coisa, tentei com um botão do primefaces e não funcionou, quando eu utilizo um botão do JSF funciona, creio eu que é algum bug do prime não poder alterar o nome do botão pelo JavaScript.

Blz!

Mostra aí como funcionou pra vc !

Então…

Página:

<?xml version="1.0" encoding="UTF-8"?>
<!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:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui">
<h:head>
	<title>Teste</title>

	<script>
		function changeValue(obj, msg) {
			obj = document.getElementById(obj);
			obj.value = msg;
		}
	</script>

</h:head>

<h:body>
	<f:view>
		<h:form id="form">
			<h:commandButton value="Testar!" id="button">
				<p:ajax event="click" listener="#{testeBean.fazer}" 
					onstart="changeValue('form:button', 'Testando...')"
					oncomplete="changeValue('form:button', 'Testar!')" />
			</h:commandButton>
		</h:form>
	</f:view>
</h:body>
</html>

Bean:

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

@ManagedBean
@SessionScoped
public class TesteBean {
	public void fazer(){
		for(int i = 0; i<999999;i++){
			System.out.println(i);
		}
	}
}

O problema é, é com um botão do JSF, não do Prime… se usar um botão do Prime simplesmente não funciona.

Só uma coisa, ao invés de mudar a label do botão, você pode colocar um popup de espera na tela, ou até um .gif de “loading”. :stuck_out_tongue:

Dê uma olhada em:
http://www.primefaces.org/showcase-labs/ui/ajaxStatusScript.jsf

[]'s

Só complementando, para funcionar com o botão do Primefaces, pode usar como o exemplo que ele postou, mas com pequenas alterações.

function changeValue(obj, msg) { obj = document.getElementById(obj).children[0].innerHTML = msg; }

&lt;p:commandButton value="Testar!" id="button" actionListener="#{index.fazer}" onstart="changeValue('form:button', 'Testando...')" onsuccess="changeValue('form:button', 'Testar!')"/&gt;

Cheguei até a achar que era pelo actionListener, mas não, é pelo JS mesmo.
Por que será que ele não encontra o objeto pelo id dele quando o botão era do prime? Digo, da forma convencional.

Porque o botão prime gera um objeto botão com um spam dentro e você tem que editar o conteúdo do spam para alterar o texto.

Nunca consegui usar objetos do prime com o binding, não sei o porque ele não se comporta como os objetos JSF nativos.

kcobainnn e AmauriSpPoa :

Testei e não obtive sucesso:

Teste 1: chega no script com onstart mas não executa o actionlistener e consequentemente no onsucess

       &lt;script&gt;  
            function changeValue(obj, msg) {  
                alert("teste..");
                obj = document.getElementById(obj).children[0].innerHTML = msg;
            }  
        &lt;/script&gt;  

&lt;p:commandButton id="btnPesquisa" value="Pesquisar" actionListener="#{pedidoVendaBean.carregaListaClientes()}" update="clientes" onstart="changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisando...');" onsuccess="changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisar');"/&gt;

Teste 2: chega no script com onstart, executa o actionlistener e chega no onsucess, mas não apresenta na tela as modificações no atributo value do commandButton realizadas no script

       &lt;script&gt;  
            function changeValue(obj, msg) {  
                alert("teste..");
                obj = document.getElementById(obj);  
                obj.value = msg;  
            }  
        &lt;/script&gt;  

&lt;p:commandButton id="btnPesquisa" value="Pesquisar" actionListener="#{pedidoVendaBean.carregaListaClientes()}" update="clientes" onstart="changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisando...');" onsuccess="changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisar macho véi!');"/&gt;

Sugestões ?

Estranho, tentou utilizar action ao invés de actionListener? Apesar que não creio seria isso… Você tentou debugar e ele definitivamente não chega nem a chamar o método? Você tem certeza que o caminho do botão está certo? Digo, esse form_cad_pedido_venda01:btnPesquisa está certo? Tem como mostrar sua página toda aqui?

Nada muda com action no lugar do actionlistener;
Conforme pode ser visto, debugado com o alert("teste…" ) dentro do script;
Caminho do botão correto, como pode ser visto abaixo:

[code]<?xml version=‘1.0’ encoding=‘ISO-8859-1’ ?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<f:view xmlns=“http://www.w3.org/1999/xhtml
xmlns:f=“http://java.sun.com/jsf/core
xmlns:h=“http://java.sun.com/jsf/html
xmlns:p=“http://primefaces.org/ui
xmlns:pm=“http://primefaces.org/mobile
contentType=“text/html”
lang=“pt-br”>
<h:head>
<h:outputScript library=“js” name=“cad_pedido_venda.js” />
<h:outputScript library=“js” name=“criaobj.js” />
<h:outputScript library=“js” name=“tnaveg.js” />
<h:outputScript library=“js” name=“tnaveg-jq.js” />
<script>
function changeValue(obj, msg) {
alert(“teste…”);
obj = document.getElementById(obj);
obj.value = msg;
}
</script>
</h:head>
<h:body>
<pm:page title=“Cadastro de Pedido de Venda”>
<f:facet name=“preinit”>
<link type=“text/css” rel=“stylesheet” href="#{request.contextPath}/resources/css/cssLayout.css" />
<link type=“text/css” rel=“stylesheet” href="#{request.contextPath}/resources/css/default_MOBILE.css" />
</f:facet>

        &lt;pm:view id="cad_pedido_venda01" swatch="a" &gt;
            &lt;pm:header title="Portal" fixed="true" swatch="b" &gt;
                &lt;f:facet name="left"&gt;&lt;p:button value="Retornar ao menu" icon="back" href="main_mobile_cad_pedido_venda.jsf" /&gt;&lt;/f:facet&gt;
                &lt;h:form&gt;
                    &lt;p:commandButton value="Sair" icon="back" action="#{inicial.logout()}" /&gt;
                &lt;/h:form&gt;
                Tela 1: Cadastro de Pedido de Venda - Escolha do cliente
            &lt;/pm:header&gt;
            &lt;pm:content&gt;
                &lt;h:form id="form_cad_pedido_venda01"&gt;
                    &lt;p:growl id="msgs01" showDetail="true" /&gt;
                    &lt;p:focus for="nome_cliente" /&gt;
                    &lt;h:outputLabel value="Buscar cliente por: " /&gt;
                    &lt;p:inputText id="nome_cliente" value="#{pedidoVendaBean.pedido.cliente.nome_cliente}" type="text" onkeydown="return ProxInput(this, event)"  onkeyup="this.value = this.value.toUpperCase();" /&gt;
                    &lt;p:commandButton id="btnPesquisa" value="Pesquisar"
                                     actionListener="#{pedidoVendaBean.carregaListaClientes()}"
                                     update="clientes"
                                     onstart="changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisando...');"
                                     onsuccess="changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisar macho véi!');"/&gt;
                    &lt;p:dataTable id="clientes" var="cli" value="#{pedidoVendaBean.mediumClienteCgc}"
                                 selectionMode="single" selection="#{pedidoVendaBean.clienteSelecionado}"
                                 rowStyleClass="#{cli.saldoEmAtraso gt 0 ? 'vermelho' : cli.saldoEmAberto le 0 ? 'verde' : 'amarelo' }"
                                 emptyMessage="Informe acima a primeira letra ou parte da razão social ou CNPJ. Em seguida clique no botão 'Pesquisar' e depois no cliente desejado." &gt;
                        &lt;p:ajax event="rowSelect" listener="#{pedidoVendaBean.onRowSelectCliente}"
                                update=":form_cad_pedido_venda01:msgs01 :cad_pedido_venda02 :cad_pedido_venda03 :cad_pedido_venda04" /&gt;
                        &lt;p:column&gt;
                            &lt;h:outputText value="#{cli.codigo_cliente} - #{cli.loja_cliente}" /&gt;&nbsp;&nbsp;
                            &lt;h:outputText value="#{cli.cgc}" &gt;
                                &lt;f:converter converterId="cnpjConverter" /&gt;
                            &lt;/h:outputText&gt;<br />
                            &lt;h:outputText value="#{cli.nome_cliente}" /&gt;<br />
                            &lt;h:outputText value="#{cli.nome_reduzido}" /&gt;<br />
                            &lt;h:outputText value="#{cli.bairro} #{cli.cidade}-#{cli.uf}" /&gt;<br />
                            &lt;h:outputText value="Email NF-e: #{cli.emailNFE}" /&gt;<br />
                        &lt;/p:column&gt;
                    &lt;/p:dataTable&gt;<br />
                    &lt;h:outputText value="Legenda: " style="font-weight: bold"/&gt;
                    &lt;h:outputText value="Sem títulos em aberto ou atraso; " styleClass="verde" /&gt;
                    &lt;h:outputText value="Saldo títulos a vencer &gt; 0; " styleClass="amarelo" /&gt;
                    &lt;h:outputText value="Saldo títulos em atraso &gt; 0." styleClass="vermelho" /&gt;
                &lt;/h:form&gt;
            &lt;/pm:content&gt;
        &lt;/pm:view&gt;


</pm:page>
</h:body>
</f:view>[/code]

o seu form está dentro de outros componentes, ao passar o id do botão tente colocar toda a hierarquia, não só a partir do form.

[]'s

Para confirmar o id do seu botão você pode colocar o código abaixo nele para mostrar o id, depois retira para não ficar sujeira no seu codigo

onclick="alert(this.id);"

O onclick=“alert(this.id);” retorna form_cad_pedido_venda01:btnPesquisa

Usando o seguinte script,no primeiro pressionar do botão o primeiro alert aparece com nada, ao invés de trazer o “Pesquisar” que é o value inicial do botão. já o alert seguinte traz o value correto, obtido pelo parâmetro msg. Já na execução do onsucess, os dois alerts do script retornam os values corretos, os quais foram postos por este script.

&lt;script&gt; function changeValue(obj, msg) { obj = document.getElementById(obj); alert(obj.value); obj.value = msg; alert(obj.value); } &lt;/script&gt;

No navegador, pedindo para exibir o código-fonte, temos o seguinte:

&lt;script&gt; function changeValue(obj, msg) { obj = document.getElementById(obj); alert(obj.value); obj.value = msg; alert(obj.value); } &lt;/script&gt; ... &lt;button id="form_cad_pedido_venda01:btnPesquisa" name="form_cad_pedido_venda01:btnPesquisa" type="submit" data-iconpos="left" onclick="PrimeFaces.ab({source:'form_cad_pedido_venda01:btnPesquisa', update:'form_cad_pedido_venda01:clientes', onstart:function(cfg){changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisando...');;}, onsuccess:function(data,status,xhr){changeValue('form_cad_pedido_venda01:btnPesquisa', 'Pesquisar macho véi!');;}}); return false;"&gt;Pesquisar &lt;/button&gt;

Percebe-se que é um refresh no componente botão que se faz necessário, antes do retorno do método do actionlistener. se for usado btnPesquisa dentro do atributo update do commandbutton ele fica adicionando um commandbutton dentro do outro. bug do primefaces.

<p:commandButton id="btnPesquisa" value="#{pedidoVendaBean.textoBotao}" action="#{pedidoVendaBean.carregaListaClientes()}" oncomplete="#{pedidoVendaBean.habilitar()}" disabled=""#{pedidoVendaBean.botaoDesabilitado} update="clientes, btnPesquisa"/>

@Named(value = "pedidoVendaBean")  
@SessionScoped  
public class PedidoVendaBean implements Serializable {  
   private boolean botaoDesabilitado;
   private String textoBotao;

   // get e set

   public PedidoVendaBean() {  
        botaoDesabilitado = false;
        textoBotao = "Pesquisar"
   }  

   public void carregaListaClientes() {  
        // ...
        botaoDesabilitado = true;
        textoBotao = "Carregando"
   }  

   public void habilitar() {  
        // ...
        botaoDesabilitado = false;
        textoBotao = "Pesquisar"
   }  


}

Tenta assim

Olá Valério,

Obrigado pela participação. Como havia dito, se coloco btnPesquisa dentro do atributo update do p:commmandButton, começa a replicá-lo no form, ficando um botão dentro do outro.

Fazendo alguns pequenos acertos na sua sugestão (ex.: falta de ; e "), realizei novamente os testes.

Percebi ao debugar que os atributos oncomplete e onsucess(tb testei, substituindo o oncomplete sugerido por vc) são chamados primeiro que o action ou actionlistener. Assim, o botão fica desabilitado quando tento clica novamente nele, após o retorno do método. Contudo seu value não se modifica em nenhum momento.

Cara testa isso aqui no seu ambiente fora dessa tela, se não funcionar não sei o que pode ser:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&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:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"&gt; &lt;h:head&gt; &lt;title&gt;Teste&lt;/title&gt; &lt;script&gt; function changeValue(obj, msg, disable) { obj = document.getElementById(obj) obj.children[0].innerHTML = msg; if(disable){ obj.setAttribute("class",obj.getAttribute("class")+" ui-state-disabled"); obj.setAttribute("disable","disable"); obj.setAttribute("aria-disabled",disable); }else{ obj.setAttribute("class",obj.getAttribute("class").replace(" ui-state-disabled", "")); obj.removeAttribute("disable"); obj.setAttribute("aria-disabled",disable); } } &lt;/script&gt; &lt;/h:head&gt; &lt;h:body&gt; &lt;f:view&gt; &lt;h:form id="form"&gt; &lt;p:commandButton value="Testar!" id="button" actionListener="#{index.fazer}" onstart="changeValue('form:button', 'Testando...', true)" onsuccess="changeValue('form:button', 'Testar!', false)" /&gt; &lt;/h:form&gt; &lt;/f:view&gt; &lt;/h:body&gt; &lt;/html&gt; [code]@ManagedBean
@ViewScoped
public class Index {

public void fazer() {
    for (int i = 0; i &lt; 99999; i++) {
        System.out.println(i);
    }
}
...}[/code]

Coloquei os seguintes alert() para debugar a função em javascript:

&lt;script&gt; function changeValue(obj, msg, disable) { alert('iniciando'); obj = document.getElementById(obj) alert(obj.children[0].innerHTML); obj.children[0].innerHTML = msg; alert(obj.children[0].innerHTML); if(disable){ alert('entrou no if'); obj.setAttribute("class",obj.getAttribute("class")+" ui-state-disabled"); obj.setAttribute("disable","disable"); obj.setAttribute("aria-disabled",disable); }else{ alert('entrou no else'); obj.setAttribute("class",obj.getAttribute("class").replace(" ui-state-disabled", "")); obj.removeAttribute("disable"); obj.setAttribute("aria-disabled",disable); } alert('saiu'); } &lt;/script&gt;

Testes realizados:

(Teste 1) do jeito que você colocou o MB, retirando apenas o “…” do final, chegou até o alert(‘iniciando’); e alí parou,sem erro no console.

(Teste 2) mesmo código testado no teste 1, removendo apenas o onstart e o onsuccess do botão, gerou o seguinte erro:[color=red]
SEVERE: ‘javax.el.PropertyNotFoundException’ recebido ao invocar escuta de ação ‘#{index.fazer()}’ para o componente ‘button’
SEVERE: javax.el.PropertyNotFoundException: /teste.xhtml @36,93 actionListener="#{index.fazer()}": Target Unreachable, identifier ‘index’ resolved to null
[/color]

(Teste 3) Consegue-se executar o método index.fazer() quando feito teste semelhante ao teste 2, alterando o MB para o seguinte abaixo:

@Named(value = &quot;index&quot;)
@ViewScoped
public class Index implements Serializable {

    public void fazer() {
        for (int i = 0; i &lt; 99999; i++) {
            System.out.println(i);
        }
    }

    public Index() {
    }
}

(Teste 4) Obtive sucesso da seguinte forma: teste semelhante ao teste 3, modificando o script para :

[code] <script>
function changeValue(obj, msg, disable) {
alert(‘iniciando’);

            obj = document.getElementById(obj);
            alert(obj.value);
            obj.value = msg;
            alert(obj.value);

            if(disable){  
                alert('entrou no if');
                obj.setAttribute("class",obj.getAttribute("class")+" ui-state-disabled");   
                obj.setAttribute("disable","disable");   
                obj.setAttribute("aria-disabled",disable);   
            }else{  
                alert('entrou no else');
                obj.setAttribute("class",obj.getAttribute("class").replace(" ui-state-disabled", ""));   
                obj.removeAttribute("disable");   
                obj.setAttribute("aria-disabled",disable);   
            }  
            alert('saiu');
        }  
    &lt;/script&gt;    

[/code]

Vou verificar onde ocorre o problema no meu código e postarei aqui a causa. Obrigado a todos!

Correção:

No teste 4 a única coisa que não aconteceu foi renomear o botão. Funcionou o fato dele ficar desabilitado enquanto não retornava da execução do método.