Exemplo Composite + JSF2

Wednesday, 3. August 2011

Para criar um componente usando Composite no JSF2 é bem simples. Abaixo vou mostrar um componente que criei para um caso em específico, basta abstrair e usar para o que precisar.

No meu caso, o meu projeto fazia uso do primefaces, então caso você use alguma outra biblioteca, basta substituir pelos componentes correspondentes aos que eu usei do primefaces.

Mãos a obra:

Pra começar, existe um padrão em que deve ser criado uma pasta chamada “resources” dentro da “webapp”, e dentro dela a pasta que será a base de sua lib de componentes, no nosso caso: “telefone”.

Dentro da pasta “telefone” crie uma xhtml que será o seu componente em sí, telefone.xhtml:

<!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:cc="http://java.sun.com/jsf/composite"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:p="http://primefaces.prime.com.tr/ui">

<cc:interface>
	<cc:attribute name="telefoneExclusao" required="true" />
	<cc:attribute name="propertyListaTelefone" required="true" />
	<cc:attribute name="actionNovoTelefone"
		method-signature="void action()" />
	<cc:attribute name="actionExcluirTelefone"
		method-signature="void action()" />
</cc:interface>

<cc:implementation>

	<p:panel header="#{msg['label_componente_telefone_listaTelefones']}">

		<f:facet name="options">
			<p:menu>
				<p:menuitem value="#{msg['label_novo']}"
					action="#{cc.attrs.actionNovoTelefone}" ajax="false" />
			</p:menu>
		</f:facet>

		<p:dataTable value="#{cc.attrs.propertyListaTelefone}" var="item"
			id="listaTelefone" update="@form" >

			<p:column>
				<f:facet name="header">

				</f:facet>
				<p:inputMask mask="9999-9999" value="#{item.numero}" />
			</p:column>
			<p:column>
				<f:facet name="header">
					<h:outputText value="#{msg['label_ramal']}" />
				</f:facet>
				<p:inputMask mask="9999" value="#{item.ramal}" />
			</p:column>
			<p:column>
				<f:facet name="header">
					<h:outputText value="#{msg['label_observacao']}" />
				</f:facet>
				<p:inputText value="#{item.observacao}" />
			</p:column>
			<p:column>
				<f:facet name="header">
					<h:outputText value="#{msg['label_excluir']}" />
				</f:facet>
				<p:commandButton value="#{msg['label_excluir']}"
					action="#{cc.attrs.actionExcluirTelefone}">
					<f:setPropertyActionListener
						target="#{cc.attrs.telefoneExclusao}" value="#{item}" />
				</p:commandButton>
			</p:column>
		</p:dataTable>
	</p:panel>
</cc:implementation>
</html>

Algumas considerações devem ser feitas sobre meu componente acima, por exemplo:

value=#{msg['label_novo']}

Essa variável msg é um Helper que eu criei para buscar valores do meu Bundle, no caso de quem estiver fazendo isso do zero, basta usar value=”Novo” que vai funcionar perfeitamente.

Quanto a minha interface:

<cc:interface>
	<cc:attribute name="idTelefoneExclusao" required="true" />
	<cc:attribute name="propertyListaTelefone" required="true" />
	<cc:attribute name="actionNovoTelefone"
		method-signature="void action()" />
	<cc:attribute name="actionExcluirTelefone"
		method-signature="void action()" />
</cc:interface>

Você irá precisar passar para o componente <telefone:telefone> os seguintes atributos:

telefoneExclusaoactionNovoTelefoneactionExcluirTelefone

<f:setPropertyActionListener target="#{cc.attrs.telefoneExclusao}" value="#{item}" />

No meu TesteMBean.java criei as entidades e métodos a seguir:

	private List<TelefoneEntity> listaTelefone;
	private TelefoneEntity telefoneExclusao;

	@PostConstruct
	public void initialize() {
		if(conversation.isTransient())
			conversation.begin();

		listaTelefone = new ArrayList();
		TelefoneEntity o = new TelefoneEntity();

		o.setId(1L);
		o.setNumero("1231-2223");
		o.setObservacao("obs");
		listaTelefone.add(o);
	}

	public void excluirTelefone(){
		telefoneExclusao.getId(); // crie aqui seu metodo de excluir o telefone
	}

	public void novoTelefone(){
		if(listaTelefone == null){
			listaTelefone = new ArrayList();
		}
		TelefoneEntity o = new TelefoneEntity();

		o.setId(2L);
		o.setObservacao("novo");
		listaTelefone.add(o);
	}

Meu TesteMBean é apenas um exemplo, pois cada um deve implementar conforme as suas necessidades.

Por fim, para usar o componente basta apenas chamá-lo passando os parametros correspondentes aos que criamos.

<telefone:telefone
   propertyListaTelefone="#{testeMBean.listaTelefone}"
   actionExcluirTelefone="#{testeMBean.excluirTelefone}"
   actionNovoTelefone="#{testeMBean.novoTelefone}"
   telefoneExclusao="#{testeMBean.telefoneExclusao}" />

Não esquecendo de importar o componente lá no cabeçalho do xhtml:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:p="http://primefaces.prime.com.tr/ui"
	xmlns:telefone="http://java.sun.com/jsf/composite/telefone">

Ele ficará assim:

Componente telefone

Componente Telefone