Dúvida e Erro Ajax4JSf

27 respostas
felipeguerra

Bom dia srs,

Estou com um seguinte problema com esse framework. Como não possuo experiência, capaz que muitos achem que o que será abordado seja muito simples, enfim…

Eu tenho uma página JSP, nela alguns divs que iniciarão ocultos, a idéia é apresentá-los de acordo com a necessidade do usuário, trata-se de uma página de inclusão, alteração e exclusão de usuários do sistema!

Pois bem, a dúvida é a seguinte:

1 - Usando as tags do A4J, como faço para executar um método assíncrono após a validação de determinados campos? (Por enquanto só sei usar o commandButton)
2 - Posso ter mais de uma tag <h:form> na mesma página para “separar” as divs e suas funcionalidades?
3 - Quando uso o atributo required=“true”, ele apresenta uma mensagem no console do Tomcat, só que, mesmo com a tag <h:message> no seu devido lugar, a mensagem correspondente ao campo não é apresentada, no que o Ajax4Jsf está interferindo no ciclo de vida do JSF?

Abraço!

27 Respostas

Leozin

E ae blza?

Vamos por partes

Poderia ser mais específico? Você quer fazer uma chamada AJAX só depois que determinados campos são validados?

Antes me responda: essa validação é cliente-side ou server-side?

Sim e deve, fica até “mais legível”, mais leve e mais fácil de dar manutenção

Se você está querendo fazer validações server-side com ajax, o “mais sugerível” (rsrsrs) é tu fazer assim:

<a4j:outputPanel ajaxRendered="true"> <h:messages /> </a4j:outputPanel>

Toda vez que tu faz uma chamada ajax, todo e qualquer componente que esteja dentro de um panel com ajaxRendered vai ser renderizado novamente SEM NECESSIDADE da propriedade “reRender” do a4j:support

felipeguerra

Leozin:
E ae blza?

Vamos por partes

Poderia ser mais específico? Você quer fazer uma chamada AJAX só depois que determinados campos são validados?

Antes me responda: essa validação é cliente-side ou server-side?

Isso mesmo, só quando determinados campo forem validados! Cliente-Side!

No servidor é mais fácil, pelo o que vc me disse, vou deixar minhas tags <h:message> dentro dessa outra tag do A4J que citou para dar as mensagens de erro, né não?

Valeu, camarada.

felipeguerra

UP!

felipeguerra

Eu queria saber se alguém já fez um combo ser populado via a4j no evento onchange?

Alguma luz?

felipeguerra

Eu não achei nenhum material bom (nem em inglês) com o passo-a-passo do ajax4jsf!

Por exemplo, tenho um form de usuário, ao submitar o mesmo, os dados devem ser validados e um usuário novo cadastrado no BD!

Pois então, na tag <a4j:commandButton /> existe a propriedade oncomplete que executa um script que eu desejar.
Como devo validar o retorno da inserção AJAX? Eu tenho as tags <h:message /> para os campos com validações que vão apresentar as minhas mensagens customisadas, só que eu não consigo sincronizar um erro de validação com o retorno do método.

Ou seja:

&lt;a4j:commandButton oncomplete="alert('Cadastro concluído com sucesso');" id="btnCadastro"  value="Cadastrar" action="#{controleUsuarioBean.inserir}" styleClass="input_button2" /&gt;&nbsp;&nbsp;

Não adianta eu ter esse trecho de código: oncomplete=“alert(‘Cadastro concluído com sucesso’);” sem que haja condições para ser apresentado, certo?

Obrigado.

felipeguerra

Ninguém?

Leozin

meu, não fica postando UP e ALGUÉM e afins cara. Ficar floodando pra galera resolver o teu problema não vai ajudar em nada, sem contar que dá a impressão que a gente tem obrigação de ajudar. Minha sugestão: se tu não consegue fazer a parada, tenta ler desde o início a documentação, vai na calma... e assim por diante

mas vamos lá

o que tu poderia fazer é o seguinte, vamos imaginar a tua página assim como vou fazer agora. Pega esse exemplo e vê se tu entende

Vamos criar aqui 3 campos: um com ID, outro com Nome e outro com Data

<h:form>
	<h:panelGrid columns="2">
		<h:outputText value="ID" />
		<h:inputText value="#{meuBean.id}" required="true"/>
			
		<h:outputText value="Nome" />
		<h:inputText value="#{meuBean.nome}" required="true">
			<f:validateLength minimum="4" maximum="10"/>
		</h:inputText>
					
		<h:outputText value="Data de Nascimento" />
		<h:inputText value="#{meuBean.dataNascimento}" required="true">
			<f:convertDateTime pattern="dd/MM/yyyy"/>
		</h:inputText>
	</h:panelGrid>
				
	<a4j:outputPanel rendered="true">
		<h:messages layout="table" />
	</a4j:outputPanel>
				
	<h:panelGrid columns="2">
		<h:commandButton value="Limpar" type="reset" />
		<h:commandButton value="Cadastrar" type="button">
			<a4j:support event="onclick" actionListener="#{meuBean.salvar}" />
		</h:commandButton>
	</h:panelGrid>
</h:form>

O teu bean

public class MeuBean {
  private int id;
  private String nome;
  private Date dataNascimento;
  
  private TesteDAO testeDAO;

  private void adicionarMensagem (String mensagem) {
    FacesMessage mensagem = new FacesMessage( mensagem, null );
    FacesContext.getCurrentInstance().addMessage( null, mensagem );
  }

  public void salvar (ActionEvent e) {
    // Vamos fazer uma validação assim: O ID não pode ser 3 porque esse número é reservado pra você
    if (id == 3)
      adicionarMensagem ("Esse número é inválido porque EU não quero que você use" );
    else {
      try {
        testeDAO.salvarTeste( new Teste (id, nome, dataNascimento );
         adicionarMensagem ("A parada foi salva com sucesso" );  
      }
      catch (Exception ex) {
         adicionarMensagem ("Erro ao salvar a parada: " + ex.getMessage() );
         ex.printStackTrace();
      }
  }

  // getters e setters
}

Você vai perceber uma coisa legal: Tente botar uma letra no ID, bote menos de 3 chars no teu campo nome e bote uma data toda errada, tipo 39103912. Antes de ele chamar o teu método, ele vai fazer uma validação padrão do JSF. Como você está fazendo essa validação pro AJAX, tu vai ver que quando tu clicar no botão salvar, vai aparecer automanticamente as messages. Tente preencher certinho e no ID, bote 3. Vai aparecer a mensagem que você inseriu no backing bean, no método "adicionarMensagem".

Veja ae se funciona :)

felipeguerra

Vc ta certo!

E mais uma coisa, já te falaram que vc é o cara?

Falou

Leozin

felipeguerra:
Vc ta certo!

E mais uma coisa, já te falaram que vc é o cara?

Falou

hahaha

testou ae? funcionou?

ah e de boa, não leva pro lado pessoal aquilo que falei no início hehe foi só mais um puxão de orelha rsrs

felipeguerra

Tranquilão, camarada!

Eu to começando a fazer umas paradas aqui. Mas é que vc tem que concordar comigo, só ler a especificação não ajuda a fazer funcionar, né?

Não tem jeito, nesses casos nada substitui a experiência…aqui mesmo no trampo, os mais juniors têm problemas direto em registrar um recurso JNDI no contexto da aplicação, eu já acho simples! Sacou?

Sâo muitas dúvidas sobre JSF e afins…

felipeguerra

Ou camarada, me diz uma coisa, se eu tenho um componente h:selectManyCheckbox, no Bean eu preciso ter um atributo do tipo: List<SelectItem>, para pegar os checkbox selecionados, correto?

Leozin

Cara não conheço porque nunca precisei usar esse componente, mas se for igual o h:selectManyListBox, a tua propriedade do bean deve ser um List<String> (pra funcionar com todos) ou tu bota um converter (que no meu caso, eu fiz um EnumConverter e não funcionou :frowning: )

felipeguerra

Converter é uma boa, aliás, eu gostei dos componentes que interferem no ciclo do JSF!

felipeguerra

Leozin:

Cara não conheço porque nunca precisei usar esse componente, mas se for igual o h:selectManyListBox, a tua propriedade do bean deve ser um List<String> (pra funcionar com todos) ou tu bota um converter (que no meu caso, eu fiz um EnumConverter e não funcionou :frowning: )

Tanto List<String>, List<SelectItem>, List<Integer>…nada funciona.
:frowning:

Leozin

que erro que tá dando?

felipeguerra

O engraçado é que não há erro, eu fiz umas alterações aqui no meu código - basicamente retirei a tag do tomahawk e deixei só o core do SUN-RI - da uma olhada (na humildade):

JSP

&lt;h:selectManyCheckbox layout="pageDirection" value="#{controleUsuarioBean.checkMenu}" required="true" immediate="true" id="chkMenu"&gt;
	&lt;f:selectItems value="#{controleUsuarioBean.listMenu}" /&gt;
&lt;/h:selectManyCheckbox&gt;
.
.
.
&lt;a4j:commandButton style="margin:2px; float: right;" ignoreDupResponses="true" ajaxSingle="true" action="#{controleUsuarioBean.cadastrarMenu}" id="btnIncluirMenu" value="Incluir" styleClass="input_button2" /&gt;

Bean

private List&lt;String&gt; checkMenu = null;

//gets e sets

	public String cadastrarMenu() {
		
		try {
			System.out.println(checkMenu); //SEMPRE IMPRIME null
			
		}catch(Throwable t) {
			MBeanUtil.logError("Erro ao cadastar o(s) menu(s).", t);
			MBeanUtil.addMessage("formInclusaoMenu", "Ocorreu um erro ao tentar consultar os perfis de usuário.");
		}
		return null;
	}

O problema: o valor não é setado na váriavel (checkMenu).

felipeguerra

Leozin,

Infelizmente tenho que encher mais um pouco.

Aquele exemplo que vc deu nesse tópico, então, no meu caso está ocorrendo um problema. As proprieadades que do meu Bean que estão associadas ao form, quando eu submito a página para ‘salvar’ eles chegam sempre vazios. Parece que nunca são populados.

Valeu

felipeguerra

Preciso estudar mais a especificação, ao colocar o atributo ajaxSingle=‘true’, ocorreu esse problema…

Agora estou resolvendo o resto.

Falou

Leozin

só uma dúvida

esse teu backing bean é de request?

EDIT: ajaxSingle nesse caso não deve ser usado, porque ele funciona da seguinte maneira: SE um componente “ajaxied” chamar uma função no backing bean e, o value dele estiver atrelado a uma propriedade do backing bean, SOMENTE ESSA PROPRIEDADE vai ser setada, ou seja, essa chamada ajax vai ser “quase” um immediate

por exemplo

<h:form> <h:inputText value="#{meuBean.inputRequired}" required="true"/> <h:inputText value="#{meuBean.inputAjax}"> <a4j:support event="onblur" actionListener="#{meuBean.funcaoXXX}" /> </h:inputText> </h:form>

agora vamos imaginar a seguinte situação: Você coloca um valor no campo inputAjax e quer validar ele quando o campo perder o foco (onblur)
A funcaoXXX vai ser chamada SOMENTE se o campo acima (o inputRequried) for preenchido. Por que? Porque por trás dos panos acontece um submit do form :slight_smile: E como o form não passou na validação (ou seja, o inputRequired não tem nenhum valor) a função do backing bean não vai ser chamada

Agora se você colocar um ajaxSingle=“true” no a4j:support, ele não vai querer validar os outros campos, somente no que está rolando a chamada ajax

o ajaxSingle deve ser usado somente em situações bem específicas, por exemplo, em um h:selectOneMenu dinâmico (ou seja, você seleciona uma opção e preenche um outro h:selectOneMenu).

O immediate se comporta de forma parecida, a diferença é que ele faz a chamada do método sem setar NENHUM valor, ou seja, não valida nada :slight_smile:

abraços

felipeguerra

Essas trocas de figurinhas realmente são muito boas! Ainda bem que vc tem paciência…

Eu entendi o que vc explicou. Em outro canto do meu código, estou tentando utilizar a tag <a4j:commandLink>, meu intuito é fazer uma consulta assíncrona (que já está funcionando perfeitamente) e, num dos campos printados, ou melhor, numa coluna específica do meu dataTable, quero colocar um link para outra chamada assíncrona.
Acompanhe no meu código:

&lt;h:dataTable width="100%" value="#{controleUsuarioBean.listUsuario}" var="users" id="listaUsuarios" styleClass="tbl_cont2" headerClass="tr1" columnClasses="w5pc w5pc w20pc w10pc w5pc w10pc w5pc w5pc w20pc w10pc w5pc"&gt;
	&lt;h:column&gt;
		&lt;f:facet name="header"&gt;&nbsp;&lt;/f:facet&gt;
                //Isso é um teste
		&lt;a4j:commandLink requestDelay="3000" ignoreDupResponses="true" immediate="false" action="#{controleUsuarioBean.consultarMenu}" value="Link" /&gt;
	&lt;/h:column&gt;
&lt;/h:dataTable&gt;

Nesse caso, essa tag não faz a chamada como eu gostaria, só que, se eu retira-la de dentro da tag <h:dataTable>, passa a funcionar sem problemas!

Qual é a explicação?

felipeguerra

Leozin:
só uma dúvida

esse teu backing bean é de request?

abraços

Isso mesmo!

Leozin

na verdade esse problema de link dentro de h:dataTable acontece porque a tua lista que montou o dataTable (no caso, o value="#{meuBean.minhaLista}") veio de um request. Ou seja, o teu backing bean vai ser montado somente na chamada da requisição, que dessa forma, não faz nenhum estado de conversação. Existem alguns “workaround” pra você corrigir isso:

  • Transformar o teu backing bean em session
    ou
  • Fazer com que o o escopo do teu backing bean seja um pouco “maior”, algo menor que um session e maior que um request, em outras palavras, utilizar a tag saveState do tomahawk (bota ela fora do h:dataTable)
<t:saveStave value=#{meuBean} />

ou

  • Utilizar a tabela do tomahawk com a propriedade preserveDataModel=“true”

<t:dataTable value="#{meuBean.minhaLista"} var="xxx" preserveDataModel="true"> //....... </t:dataTable>

felipeguerra

Até o momento, acertou na mosca!

Vc recomenda algum livro para eu melhorar o conhecimento de JSF?

felipeguerra

Percebi que vc tem um conhecimento bacana sobre JSF!

Para não ter que reinventar a roda, eu faço qualquer coisa…rs.

Então, eu comecei precisando da sua ajuda para fazer o menu com jsCookMenu, não sei se vc lembra…eu consegui, ta funcionando daora!

Agora, eu queria fazer a mesma coisa, só que usando a tag <t:treeCheckbox>, não achei nada na net, por acaso vc já fez algo parecido? Meu objetivo é o seguinte, tenho o menu no BD, quero apresentá-lo de forma hierárquica para que o admin do sistema cadastre outros usuários nos menus aos quais eles não estão cadastrados.

A lógica para isso eu já tenho, no caso do jsCookMenu ele tem a inteligência para iterar, né? E o treeCheckBox, tem?

felipeguerra

Além do treeCheckBox, estou com um problema simples, mas que não consigo resolver, tenho um método que não está executando no Backin Bean, vejam o código:

&lt;h:commandButton type="button" id="btnAlterar" rendered="#{login.flagAlteracaoSenha}" value="#{customMessage.login_btn_alterar}" styleClass="input_button"&gt;
    &lt;a4j:support action="#{login.alterarsenha}" ignoreDupResponses="true" /&gt;
&lt;/h:commandButton&gt;
felipeguerra
rendered="#{login.flagAlteracaoSenha}"

Isso está interferindo no funcionamento do botão, sempre que eu deixo com essa propriedade, o método no backing bean não é invocado, sem ela, funciona perfeitamente!

Alguém sabe o que é?

Leozin

bota ajaxSingle=“true” no teu componente a4j:support pra ver o que acontece

Ps.: se você estiver utilizando o JSF 1.2, lhe sugiro a retirar o h:commandButton e usar o do tomahawk (t:commandButton)

uma coisa que percebi é que mesmo você colocando h:commandButton type=“button” ele se transforma num submit, ou seja, ele até faz a chamada ajax, mas ele dá um submit na página e vai rolar um refresh

abraço

Criado 14 de dezembro de 2007
Ultima resposta 16 de jan. de 2008
Respostas 27
Participantes 2