Um exemplo do Primefaces Autocomplete com Converter

Olá pessoal,

Segue um exemplo da tag autoComplete do Primefaces, usando um converter:

// O bean:

public class CompanyControl implements Serializable{
    
    private CompanyMemoryDao dao = new CompanyMemoryDao();
    private Company selected;
    

    public Company getSelected() {
        return selected;
    }

    public void setSelected(Company selected) {
        this.selected = selected;
    }

    // Actions
    public List<Company> completeCompany(){
        return dao.listAll();
    }
    
    public String clear(){
        this.selected = null;
        return "";
    }
}

// O converter:

public class CompanyConverter implements Converter {

    CompanyMemoryDao dao = new CompanyMemoryDao();
    
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        Company c = dao.getById( Long.parseLong(value) );
        return c;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        Company c = (Company) value;
        return String.valueOf( c.getId() );
    }

}

// A página:

<h:body>     
    <p:panel header="Auto Complete Example">
        <h:form>


            <h:panelGrid columns="2">
                <h:outputLabel value="Empresa: " />
                <p:autoComplete value="#{companyControl.selected}"
                                completeMethod="#{companyControl.completeCompany()}"
                                converter="companyConverter"
                                var="company" itemLabel="#{company.name}" itemValue="#{company}"
                                forceSelection="true">

                </p:autoComplete>

            </h:panelGrid>
            <p:commandButton value="Ver" update="show" ajax="false"/>
            <p:commandButton value="Limpar" action="#{companyControl.clear()}" ajax="false"/>

            <p:spacer height="10"/>
            
            <h:panelGroup id="show" rendered="#{not empty companyControl.selected}">
                <h2><h:outputText value="Voce selecionou a empresa: " /></h2>
                <h:panelGrid columns="2">
                    <h:outputLabel value="Empresa: " />
                    <h:outputText value="#{companyControl.selected.name}" />

                    <h:outputLabel value="Faturamento: " />
                    <h:outputText value="#{companyControl.selected.revenue}" />         
                </h:panelGrid>
            </h:panelGroup>
            
        </h:form>
    </p:panel>
</h:body>

Veja funcionando aqui:
http://codepianist.com/java-ee/primefaces-autocomplete-com-converter/

Um grande abraço e sucesso! :wink:

Olá, tudo bem?
tentei fazer o seu exemplo na aplicação, porém não funcionou, tive dificuldades de fazer o converter.
pode me ajudar?

Olá cbs_sp,

já vi varios exemplos mas, tem uma coisa que não consigo entender:

public Object getAsObject(FacesContext context, UIComponent component, String value) {
Company c = dao.getById( Long.parseLong(value) );
return c;
}

O meu value vem o Nome e não o ID… como faço para que seja enviado o id?

Outra coisa, se eu chamar assim:

completeMethod="#{companyControl.completeCompany()}

com o () não funciona, tenho que colocar assim:

completeMethod="#{companyControl.completeCompany}"

desde ja agradeço qualquer ajuda.

targas, o correto é sem () mesmo.

E se o value é o nome, você faz a pesquisa pelo nome, ou então altere o value para id.

Não sei se é o que querem, mas depois de quebrar a cabeça, consegui este resultado:

package com.portal.view;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import com.portal.empresa.Empresa;

@FacesConverter(value = "Converter")
public class EntityConverter implements Converter {

	@Override
	public Object getAsObject(FacesContext context, UIComponent component, String value) {
		if (value != null && value.trim().length() > 0) {
			try {
				Empresa empresa = new Empresa();
				empresa.setNome(value);
				return empresa;
			} catch (Exception e) {
				throw new ConverterException("Não foi possível obter a empresa." + value + "." + e.getMessage());
			}
		}
		return null;
	}

	@Override
	public String getAsString(FacesContext context, UIComponent component, Object value) {
		if (value != null && value instanceof Empresa) {
			return ((Empresa) value).getNome();
		}
		return "";

	}
}

Isso dará errado se você for alocar a empresa em um funcionário, por exemplo, e depois tentar persistir. Precisa do Id da empresa. Ou você coloca o Id da empresa no value, ou então pega o nome e depois procura pelo banco usando o nome da empresa.

isso foi criado só pra obter valores em um autocomplete do Primefaces, então, só deve mostrar, até agora não deu errado, mas, qual a sua sugestão?

Se for só para mostrar, ai tudo bem. Agora se precisar de outros dados da empresa, teria que colocar isso no try do getAsObject:

 Empresa empresa = new Empresa();  
 empresa.setNome(value); 
 empresa = new EmpresaDAO().consultarPorNome(empresa);
 return empresa;

Funciona bem se o campo nome na tabela da empresa for único.

Caro ErickRAR,

obrigado pelas resposta, no entanto, alterar o value para ID não da certo, preciso passar o objeto todo:

<p:autoComplete value="#{setoresBean.empresaSelecionada}"
id=“cmbEmpresas”
completeMethod="#{setoresBean.autocompletarEmpresas}"
var=“p”
itemLabel="#{p.pessoa.nomeRazaoSocial}"
itemValue="#{p}" /// Seria aqui que vc fala para trocar pelo ID??
converter=“empresasConverter”
forceSelection=“true”
dropdown=“true”
size=“40”
maxlength=“40”
required=“true”
requiredMessage=“Compo Obrigatório!”>
</p:autoComplete>
<p:message for=“cmbEmpresas”/>

Não, é na criação do SelectItem.

List<SelectItem> itens = new ArrayList<SelectItem>(); List<Empresa> empresas = empresaDAO.listar(); for (Empresa e : empresas) { //new SelectItem(Valor,Label) itens.add(new SelectItem(empresa.getIdEmpresa(), empresa.getNome())); } return itens; }
Aqui tem um exemplo, meio bagunçado, mas funciona. Só arrumar.

Uso isso na listagem:

[code] @SuppressWarnings(“unchecked”)
public List<Empresa> buscarPorNome(String nome, int startingAt, int maxPerPage) {
Criteria query = this.session.createCriteria(Empresa.class).add(Restrictions.ilike(“nome”, nome, MatchMode.ANYWHERE)).addOrder(Order.asc(“prioridade”));
query.setFirstResult(startingAt);
query.setMaxResults(maxPerPage);
return query.list();

}

[/code]
Sugestão para o nosso colega, uso isso na view, juntamente como o converter, que anteriormente foi passado:

&lt;p:autoComplete id="complete" value="#{empresaBean.empresa}"
						var="empresa" completeMethod="#{empresaBean.autocompleteEmpresa}"
						itemLabel="#{empresa.nome}" itemValue="#{empresa}"
						onkeyup="this.value = this.value.toUpperCase();" maxResults="9"
						size="80" converter="Converter" required="true"
						requiredMessage="Digite um nome para pesquisa." /&gt;
					&lt;div id="btn"&gt;
						&lt;h:commandLink actionListener="#{empresaBean.buscarPorNome}"
							update="empresasTable"&gt;
							&lt;h:graphicImage library="images" name="botao.png" width="118"
								height="27" style="border:0" /&gt;
						&lt;/h:commandLink&gt;

O resultado é obtido corretamente, passo o nome e obtenho o valor requerido.
no Bean fiz isso:

o autoComplete:

public List&lt;Empresa&gt; autocompleteEmpresa(String query) { List&lt;Empresa&gt; queryResults = new ArrayList&lt;Empresa&gt;(); if (this.empresas == null) { this.empresas = empresaRN.complete(); } for (Empresa e : empresas) { if (e.getNome().startsWith(query)) { queryResults.add(e); } } return queryResults; }
e o método busca por nome:

public List&lt;Empresa&gt; buscarPorNome() { if (this.empresas == null) { String nome = empresa.getNome(); empresas = empresaRN.buscaPorNome(nome, startingAt, maxPerPage); } return this.empresas; }
onde empresas é uma lista, carregada no bean:

private List&lt;Empresa&gt; empresas;

e o autocomplete tem este comportamento no DAO,ou seja, obtenho tudo a partir de um nome, onde é convertido quando necessário à partir do converter, anteriormente passado.:

[code] @SuppressWarnings(“unchecked”)
public List<Empresa> complete() {
Query query = this.session.createQuery(“Select e From Empresa as e order by e.prioridade ASC”);
return query.list();

}[/code]

Olá pessoal, sou novo aqui no forum e no jsf… estou com um problema em relação ao autocomplete e converter.

O auto complete está funcionando perfeitamente, uso ele em um campo endereço no formulario, que me mostra todos os endereços cadastrados no banco de dados. O que ocorre é que, quando vou olhar meu banco de dados ou preciso editar um cadastro que contem o endereço inserido atraves do autocomplete, o mesmo fica como: entidades.Client@293b53 (o valor dpois do @ sempre muda a cada inserção). Acredito que o erro seja no converter, porem já alterei várias vezes o converter, testei vários exemplos aqui do forum e até agora o problema continua.

Utilizo primefaces 3.3.1+hibernate+mysql 5+eclipse helios. Alguem pode me dar uma força?

Obrigado.

segue o codigo do converter:

package converter;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

import controller.ClientBean;
import entidades.Client;

@FacesConverter(value="converter")
public class enderecoConverter implements Converter {
	@Override  
	public Object getAsObject(FacesContext fc, UIComponent uic, String cli_endereco) {   
	    // ClientBean clientBean = new ClientBean();
	    // return  clientBean.complete(cli_endereco);
		if (cli_endereco != null && cli_endereco.isEmpty())
			return null;
		Client client = new Client();
		client.setCli_endereco(cli_endereco);
		return client;
	}  
	  
	@Override  
	public String getAsString(FacesContext fc, UIComponent uic, Object o) {  
	       //Client client = new Client();  
	       //client = (Client) o;  
	       //return client.getCli_endereco();
		return ((Client)o).getCli_endereco();
	    }
}

Tente setar o objeto pelo qual necessita passar através do converter, o que passei está funcional, é basicamente a mesma situação que você.
Tente usá-lo como exemplo:

package com.portal.view;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import com.portal.empresa.Empresa;

@FacesConverter(value = &quot;Converter&quot;)
public class EntityConverter implements Converter {

	@Override
	public Object getAsObject(FacesContext context, UIComponent component, String value) {
		if (value != null && value.trim().length() &gt; 0) {
			try {
				Empresa empresa = new Empresa();
				empresa.setNome(value);
				return empresa;
			} catch (Exception e) {
				throw new ConverterException(&quot;Não foi possível obter a empresa.&quot; + value + &quot;.&quot; + e.getMessage());
			}
		}
		return null;
	}

	@Override
	public String getAsString(FacesContext context, UIComponent component, Object value) {
		if (value != null && value instanceof Empresa) {
			return ((Empresa) value).getNome();
		}
		return &quot;&quot;;

	}
}

[quote=smnj]Tente setar o objeto pelo qual necessita passar através do converter, o que passei está funcional, é basicamente a mesma situação que você.
Tente usá-lo como exemplo:

[code]
package com.portal.view;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import com.portal.empresa.Empresa;

@FacesConverter(value = "Converter")
public class EntityConverter implements Converter {

@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
	if (value != null && value.trim().length() &gt; 0) {
		try {
			Empresa empresa = new Empresa();
			empresa.setNome(value);
			return empresa;
		} catch (Exception e) {
			throw new ConverterException(&quot;Não foi possível obter a empresa.&quot; + value + &quot;.&quot; + e.getMessage());
		}
	}
	return null;
}

@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
	if (value != null && value instanceof Empresa) {
		return ((Empresa) value).getNome();
	}
	return &quot;&quot;;

}

}
[/code][/quote]

tentei fazer como o seu exemplo porem continua com o mesmo problema. O item grava no banco como objeto e nao como string (acredito eu), pois oq vai para o banco é: entidade.client@834b54

entidade= pacote
client= minha classe java

Talvez o problema seja estar gravando como objeto;
meu e-mail é smnjr@hotmail.com
Mande, por favor seu código, vou analisar com calma até o final desta semana.

[quote=smnj]Talvez o problema seja estar gravando como objeto;
meu e-mail é smnjr@hotmail.com
Mande, por favor seu código, vou analisar com calma até o final desta semana.[/quote]

Muito obrigado pela ajuda. Estou mandando o código no seu email.

targas,

Não sei se você já resolveu a questão do ID, mas o mesmo deverá ser retornado no método getAsString do converter, assim, sendo recuperado no método getAsObject do mesmo converter. Não se preocupe pois os nomes vão aparecer na lista do autocomplete pois no atributo itemLabel você vai configurá-lo para isto.

Olá, caros, agradeço demais pela ajuda de todos, mas pretendo usar o RichFaces para esse fim, apesar de ter imensamemente gostado do Primefaces quero variar um pouco, visto que achei mais funcionalidade no Rich.
Muito obrigado.