33
6 Creación de la lista de contactos con sus detalles En este capítulo, vamos a desarrollar la parte de administración de contactos de nuestra aplicación, que incluyen listar, agregar, editar y eliminar contactos, todos al estilo Ajax. Por otra parte, vamos a aprender nuevos conceptos sobre el marco de componentes RichFaces y Ajax. El diseño principal Vamos a iniciar la preparación del espacio para las principales características de la aplicación. Como hemos visto en el capítulo 4, la aplicación, queremos un diseño en tres columnas para los grupos, la lista de contactos y los detalles del contacto. Vamos a abrir el archivo home.xhtml y agregamos un panel de cuadrículas de tres columnas en el interior del cuerpo: <h:panelGrid columns="3" width="100%" columnClasses="main-group-column, main-contacts-listcolumn, main-contact-detail-column"> </h:panelGrid> Estamos utilizando tres nuevas clases CSS (uno para cada columna). Vamos a abrir el archivo /view/stylesheet/theme.css y agregamos el siguiente código: .main-group-column { width: 20%; vertical-align: top; } .main-contacts-list-column { width: 40%; vertical-align: top; } .main-contact-detail-column { width: 40%; vertical-align: top; } Las columnas principales están listas, y ahora queremos dividir el contenido de cada columna en un archivo aparte (para no tener un archivo grande y difícil de leer) usando las capacidades de plantillas de Facelets, vamos a crear una nueva carpeta dentro de la carpeta /view llamada main y vamos a crear los siguientes archivos vacíos en su interior:

JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Embed Size (px)

DESCRIPTION

En este capítulo, vamos a desarrollar la parte de administración de contactos de nuestra aplicación, que incluyen listar, agregar, editar y eliminar contactos, todos al estilo Ajax.Por otra parte, vamos a aprender nuevos conceptos sobre el marco de componentes RichFaces y Ajax.

Citation preview

Page 1: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

6 Creación de la lista de

contactos con sus detalles

En este capítulo, vamos a desarrollar la parte de administración de contactos de nuestra aplicación, que incluyen listar, agregar, editar y eliminar contactos, todos al estilo Ajax. Por otra parte, vamos a aprender nuevos conceptos sobre el marco de componentes RichFaces y Ajax.

El diseño principal Vamos a iniciar la preparación del espacio para las principales características de la aplicación. Como hemos visto en el capítulo 4, la aplicación, queremos un diseño en tres columnas para los grupos, la lista de contactos y los detalles del contacto. Vamos a abrir el archivo home.xhtml y agregamos un panel de cuadrículas de tres columnas en el interior del cuerpo:

<h:panelGrid columns="3" width="100%" columnClasses="main-group-column, main-contacts-listcolumn,

main-contact-detail-column"> </h:panelGrid>

Estamos utilizando tres nuevas clases CSS (uno para cada columna). Vamos a abrir el archivo /view/stylesheet/theme.css y agregamos el siguiente código:

.main-group-column { width: 20%; vertical-align: top; } .main-contacts-list-column { width: 40%; vertical-align: top; } .main-contact-detail-column { width: 40%; vertical-align: top; }

Las columnas principales están listas, y ahora queremos dividir el contenido de cada columna en un archivo aparte (para no tener un archivo grande y difícil de leer) usando las capacidades de plantillas de Facelets, vamos a crear una nueva carpeta dentro de la carpeta /view llamada main y vamos a crear los siguientes archivos vacíos en su interior:

Page 2: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

• contactsGroups.xhtml • contactsList.xhtml • contactEdit.xhtml • contactView.xhtml Ahora vamos a abrirlos y escribir el código estándar para un archivo vacío (included):

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.com/products/seam/taglib" 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:rich="http://richfaces.org/rich" xmlns:a="http://richfaces.org/a4j"> <!-- my code here --> </ui:composition>

Ahora, tenemos todas las piezas listas para ser incluido en el archivo home.xhtml, vamos a abrirlo y empezar a añadir la primera columna dentro de h:panelGrid:

<a:outputPanel id="contactsGroups"> <ui:include src="main/contactsGroups.xhtml"/>

</a:outputPanel> Como puede ver, hemos encerrado include con un a:outputPanel que se utiliza como marcador de posición para la nueva presentación. Incluir una etiqueta Facelets (ui:include) dentro de a:outputPanel que hemos utilizado con el fin de incluir la página en ese punto.

Marcadores de posición de Ajax Un concepto muy importante a tener en cuenta durante el desarrollo es que el marco Ajax no puede agregar o eliminar, sólo puede reemplazar los elementos existentes en la página. Por esta razón, si desea añadir algo de código, usted necesita utilizar un marcador de posición. RichFaces tiene un componente que puede ser utilizado como un marcador de posición a4j:outputPanel. Dentro de a4j:outputPanel, puede poner otros componentes que utilizan atributos "rendered" con el fin de decidir si son visibles o no. Cuando quiera volver a representar a todos los componentes incluidos, sólo recosntruir la outputPanel, y todos funcionan sin ningún problema. Éste no es un fragmento de código que trabaja:

<h:form> <h:inputText value="#{aBean.myText}"> <a4j:support event="onkeyup" reRender="out1" /> </h:inputText> </h:form> <h:outputText id="out1"

Page 3: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

value="#{aBean.myText}" rendered="#{not empty aBean.myText}"/>

Este código parece ser el mismo que el ejemplo de a4j:support, pero no funciona. El problema es que hemos añadido el atributo rendered a outputText, por lo que inicialmente, out1 no serán rendered (ya que la propiedad de texto está vacío inicialmente rendered y será igual a false). Después de la respuesta del Ajax, el motor de JavaScript no se encuentra el out1 elemento (que no está en la página debido rendered="false"), y no podrá actualizarlo (recuerde que usted no puede añadir o eliminar elementos , sólo sustituirlos). Es muy simple de hacer que el código funcione: <h:form> <h:inputText value="#{aBean.myText}"> <a4j:support event="onkeyup" reRender="out2" /> </h:inputText> </h:form> <a4j:outputPanel id="out2"> <h:outputText id="out1" rendered="#{not empty aBean.myText}" value="#{aBean.myText}" /> </a4j:outputPanel> Como puede ver, sólo tienes que poner el componente out1 dentro A4j:outputPanel (llamado out2) y decirle a4j:support que visualice out2 en lugar de out1. Inicialmente, out2 será visualizado, pero estará vacío (porque out1 no se muestra). Después de la respuesta de Ajax, el out2 vacío serán sustituidos por elementos de marcado que también contienen el componente de out1 (que ahora es visible, porque la propiedad myText no está vacía después de la actualización del Ajax y la propiedad rendered es verdadero). Un concepto muy importante a tener en cuenta durante el desarrollo es que el marco Ajax no puede agregar o eliminar, sólo puede reemplazar los elementos existentes de la página. Por esta razón, si desea añadir algo de código, usted necesita utilizar un marcador de posición. En el ejemplo de la lista de contactos del Capítulo 3, Primeros Pasos, no usamos un marcador de posición para el contacto no encontrado h:outputText "No se han encontrado", porque los componentes de la acción Ajax (como el botón "Borrar") reconstruye el formulario que la rodea fContactsList que actúa como un marcador de posición en este caso.

El cuadro de los grupos Esta casilla contendrá todos los grupos de contactos, para que el usuario sea capaz de organizar los contactos en diferentes grupos de una mejor manera. No vamos a implementar las funcionalidades del cuadro de grupo en este capítulo. Por lo tanto, por ahora la columna de grupo es sólo un rich:panel con un enlace para actualizar la lista de contactos. Vamos a abrir el archivo contactsGroups.xhtml e insertemos el siguiente código:

<h:form> <rich:panel>

Page 4: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

<f:facet name="header"> <h:outputText value="#{messages['groups']}" /> </f:facet> <h:panelGrid columns="1"> <a:commandLink value="#{messages['allContacts']}" ajaxSingle="true" reRender="contactsList"> <f:setPropertyActionListener value="#{null}" target="#{homeContactsListHelper.contactsList}" /> </a:commandLink> </h:panelGrid> </rich:panel> </h:form>

Como puede ver, hemos puesto tres columnas h:panelGrid (que se utilizará en el futuro) y a:commandLink, que sólo establece la propiedad de contactos del bean homeContactListHelper (que veremos en la siguiente sección) a nula, a fin de que la lista se lea nuevamente. Al final la interacción de Ajax, volverá a hacer la columna de contactos a fin de mostrar los nuevos datos. También, observe que todavía estamos dando soporte a todos los mensajes de texto utilizando la propiedad messages, la tarea de llenar el archivo de messages_XX.properties se deja como ejercicio para el usuario.

La lista de contactos La segunda columna en el interior h:panelGrid de home.xhtml se ve algo como:

<a:outputPanel id="contactsList"> <ui:include src="main/contactsList.xhtml"/> </a:outputPanel>

En cuanto a los grupos, se utilizó un marcador de posición que rodean la interfaz de usuario, la etiqueta ui:include. Ahora vamos a centrarnos en la creación de la tabla de datos, abra el archivo /view/main/contactsList.xhtml y añadir el fragmento de código para el primer DataTable:

<h:form> <rich:dataTable id="contactsTable" reRender="contactsTableDS" rows="20" value="#{homeContactsListHelper.contactsList}" var="contact"> <rich:column width="45%"> <h:outputText value="#{contact.name}"/> </rich:column> <rich:column width="45%"> <h:outputText value="#{contact.surname}"/> </rich:column> <f:facet name="footer">

Page 5: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

<rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"/> </f:facet> </rich:dataTable> <h:outputText value="#{messages['noContactsInList']}" rendered="#{homeContactsListHelper.contactsList.size()==0}"/> </h:form>

Acabamos de añadir el componente rich:dataTable con algunas columnas y una barra de desplazamiento de datos Ajax al final.

Las diferencias entre h:dataTable y rich:dataTable RichFaces ofrece su propia versión de h:dataTable, que contiene más funciones y se integra mejor en el marco de RichFaces. La primera característica adicional importante, de hecho, es el soporte de la skinnability siguiendo los estándares de RichFaces. Otras características son de fila y columna con soporte extendido (lo comentaremos en la sección columnas y grupos de columnas), fuera de la caja de filtro y ordenación (que se examinan en la sección de filtrado y ordenación), más los controladores de eventos de JavaScript (como onRowClick, onRowContextMenu, onRowDblClick, y así sucesivamente) y el atributo reRender. Al igual que otros componentes de iteración de datos el marco RichFaces, también da soporte a la actualización parcial de la fila (véase el Capítulo 10, Técnicas avanzadas para más información).

Paginación de datos La implementación de paginación de datos en Ajax usando RichFaces es muy simple, sólo hay que decidir el número de filas que se mostrarán en cada página mediante el establecimiento de atributo rows de DataTable (en nuestro caso, hemos elegido 20 filas por página), y despues “adjuntamos” al componente rich:datascroller para llenar el atributo for con el ID de DataTable:

<rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"/>

Aquí puedes ver otro atributo muy útil (renderIfSinglePage) que oculta el componente cuando sólo hay una sola página en la lista (esto significa que la lista contiene un número de elementos menor o igual al valor del atributo rows) . Hay que tener en cuenta que el componente rich:datascroller debe permanecer dentro del componente de formulario (h:form o a:form) para que funcione. Es posible la personalización de componentes rich:datascroller no solo mediante el uso de clases CSS (como siempre), sino también personalizando nuestras propias piezas utilizando los siguientes facets:

• pages • controlsSeparator

Page 6: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

• first, first_disabled • last, last_disabled • next, next_disabled • previous, previous_disabled • fastforward, fastforward_disabled • fastrewind, fastrewinf_disabled

He aquí un ejemplo con algunos facets personalizados (mediante el uso de cadenas):

<rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"> <f:facet name="first"> <h:outputText value="First" />

</f:facet> <f:facet name="last"> <h:outputText value="Last" />

</f:facet> </rich:datascroller>

Aquí está el resultado:

Usted puede usar una imagen (u otro componente) en lugar de texto, con el fin de crear su scroller a su medida. Otro ejemplo interesante es la siguiente:

<rich:datascroller id="contactsTableDS" for="contactsTable" renderIfSinglePage="false"> <f:facet name="first"> <h:outputText value="First"/> </f:facet> <f:facet name="last"> <h:outputText value="Last"/> </f:facet> <f:attribute name="pageIndexVar" value="pageIndexVar"/>

<f:attribute name="pagesVar" value="pagesVar"/>

<f:facet name="pages"> <h:panelGroup> <h:outputText value="Page #{pageIndexVar} / #{pagesVar}"/> </h:panelGroup> </f:facet>

</rich:datascroller> El resultado es:

Al establecer los atributos de pageIndexVar y pagesVar, somos capaces de utilizarlos en un componente outputText, como lo hemos hecho en el ejemplo.

Page 7: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Una atributo útil de este componente es maxpages que establece el número máximo de páginas de enlaces (los números en el medio), que muestra el scroller-por lo tanto, podemos controlar el tamaño de la misma. El atributo page podría estar vinculado a una propiedad de un bean, con el fin de cambiar a una página colocando el número - un caso de uso simple podría ser utilizando un inputText y un CommandButton, a fin de que el cliente introduzca el número de página que el/ella quieran. Aquí está el código que muestra cómo implementarlo:

<rich:datascroller for="contactsList" maxPages="20" fastControls="hide" page="#{customDataScrollerExampleHelper.scrollerPage}" pagesVar="pages" id="ds"> <f:facet name="first"> <h:outputText value="First" /> </f:facet> <f:facet name="first_disabled"> <h:outputText value="First" /> </f:facet> <f:facet name="last"> <h:outputText value="Last" /> </f:facet> <f:facet name="last_disabled"> <h:outputText value="Last" /> </f:facet> <f:facet name="previous"> <h:outputText value="Previous" /> </f:facet> <f:facet name="previous_disabled"> <h:outputText value="Previous" /> </f:facet> <f:facet name="next"> <h:outputText value="Next" /> </f:facet> <f:facet name="next_disabled"> <h:outputText value="Next" /> </f:facet> <f:facet name="pages"> <h:panelGroup> <h:outputText value="Page "/> <h:inputText value="#{customDataScrollerExampleHelper. scrollerPage}" size="4"> <f:validateLongRange minimum="0" /> <a:support event="onkeyup" timeout="500" oncomplete="#{rich:component('ds')}. switchToPage(this.value)" /> </h:inputText> <h:outputText value=" of #{pages}"/> </h:panelGroup> </f:facet> </rich:datascroller>

Page 8: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Como puede ver, además de personalizar el texto de las secciones First, Last, Previous, y Next. A continuación, se define un facet pages mediante la inserción de h:inputText conectado con un valor entero dentro de un bean de respaldo. También hemos añadido la etiqueta a:support, con objeto de reducir el cambio de página después del evento keyup se ha completado. También hemos establecido el atributo de timeout, para llamar al servidor cada 500 ms y no cada vez que el usuario escriba Usted puede ver una captura de pantalla aquí:

Agregar encabezados de la columna Ahora nos gustaría agregar un encabezado para cada columna de la DataTable, la forma más sencilla es simplemente poner una faceta dentro del componente rich:column, de esta manera: <rich:column> <f:facet name="header"> <h:outputText value="my header" /> </f:facet> ... </rich:column> Este método también funciona para el componente estándar h:dataTable, RichFaces mejora las capacidades de la tabla de la partida, al permitir la agrupación, mediante el componente rich:columnGroup. Por lo tanto, volviendo a nuestra aplicación, podemos poner el siguiente código dentro de la etiqueta rich:dataTable a fin de definir el encabezado de la dataTable:

<rich:dataTable ... > <f:facet name="header"> <rich:columnGroup> <rich:column colspan="2"> <h:outputText value="Contacts"/> </rich:column> <rich:column breakBefore="true"> <h:outputText value="Name"/> </rich:column> <rich:column> <h:outputText value="Surname"/> </rich:column> </rich:columnGroup> </f:facet> ...

Y el resultado será el siguiente:

Page 9: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Columnas y grupos de columnas Con la versión de RichFaces es también muy conveniente extender el comportamiento dataTable para visualizar la fila. Echemos una versión simplificada (sin header, footer y datascroller) de la tabla contactsList:

<rich:dataTable id="contactsTable" value="#{homeContactsListHelper.contactsList}" var="contact"> <rich:column> <h:outputText value="#{contact.name}"/> </rich:column> <rich:column> <h:outputText value="#{contact.surname}"/> </rich:column> <rich:column> <a:commandButton image="/img/view.png" /> </rich:column> </rich:dataTable>

Se trata de un dataTable normal y luce así:

Ahora vamos a editar y agregar dos atributos Span y breakBefore:

<rich:dataTable id="contactsTable" value="#{homeContactsListHelper.contactsList}" var="contact"> <rich:column colspan="2"> <h:outputText value="#{contact.name}"/> </rich:column> <rich:column breakBefore="true"> <h:outputText value="#{contact.surname}"/> </rich:column> <rich:column> <a:commandButton image="/img/view.png" /> </rich:column> </rich:dataTable>

Con las características mencionadas, como se ve:

Page 10: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

¿Qué ha sucedido? Les hemos dicho a la primera columna de "span" (usted puede conocer el significado porque es un atributo estándar de una columna de tablas HTML), dos columnas y el segundo "break before", en el sentido de cierre de la fila (colocar el código HTML etiqueta </ tr>). Así, la primera columna llena el espacio de dos columnas y la segunda se visualiza en la otra fila, sencillo, ¿no? También puede utilizar el atributo rowspan con el fin de abarcar filas en lugar de columnas, como estándar para las tablas HTML. Podemos tener el mismo resultado utilizando un componente rich:columnGroup en lugar del atributo breakBefore, como en el ejemplo siguiente:

<rich:dataTable id="contactsTable" value="#{homeContactsListHelper.contactsList}" var="contact"> <rich:column colspan="2"> <h:outputText value="#{contact.name}"/> </rich:column> <rich:columnGroup> <rich:column> <h:outputText value="#{contact.surname}"/> </rich:column> <rich:column> <a:commandButton image="/img/view.png"/> </rich:column> </rich:columnGroup> </rich:dataTable>

Como podemos ver, el resultado es exactamente el mismo. Otro uso de rich:column y rich:columnGroup es definir un complejo encabezado de la tabla como lo hemos hecho en nuestra aplicación, como se muestra en la sección anterior. rich:column contiene más atributos muy útiles que span, breakBefore, filtrado y ordenación de los atributos (que vamos a ver en la siguiente sección), que no encontramos en el componente estándar h:column. Por ejemplo, en nuestra aplicación, usamos el atributo width con el fin de establecer el ancho para cada columna, sin necesidad de utilizar una clase CSS sólo para eso.

Page 11: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Característica de filtrado y ordenación Otra característica importante que hemos visto en un ejemplo sencillo en el capítulo 3 es la de que fuera de la caja hay controles de filtrado y ordenación que el componente rich:dataTable proporciona. Con el fin de añadir esta función a nuestra tabla, vamos a editar la etiqueta rich:column para el nombre y apellido, como se muestra en el siguiente código:

<rich:column width="45%" sortBy="#{contact.name}" filterBy="#{contact.name}"> <h:outputText value="#{contact.name}"/> </rich:column> <rich:column width="45%" sortBy="#{contact.surname}" filterBy="#{contact.surname}"> <h:outputText value="#{contact.surname}"/> </rich:column>

Usted tendrá la característica de filtro y ordenación para su tabla sólo agregando estos dos atributos.

En el capítulo 10, vamos a explicar de una manera más personalizada para la administración de filtrado y ordenación.

La barra de herramientas inferior Tenemos una barra de herramientas en la parte inferior de la tabla que contiene botones de acción para los diferentes tipos de acción (vamos a agregar el botón para añadir un nuevo contacto en la siguiente sección). Hemos visto a el componente rich:toolbar de la barra de herramientas en el capítulo 5, la estructura de aplicación, por lo que sólo tiene que añadir este código después del código para rich:datascroller:

<rich:toolBar> <rich:toolBarGroup> <!-- my action buttons here --> </rich:toolBarGroup> </rich:toolBar>

Page 12: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

El bean de respaldo Hemos visto la conexión de la tabla con un bean de apoyo llamado homeContactsListHelper, vamos a crearla! Vamos a crear un nuevo paquete llamado main dentro de book.richfaces.advcm.modules, y crear una nueva clase llamada HomeContactsListHelper dentro de él. El componente bean es muy simple, ya que acaba de recuperar la lista de contactos de la base de datos (los grupos no son administrados por ahora) y podría tener el siguiente aspecto:

@Name("homeContactsListHelper") @Scope(ScopeType.CONVERSATION) public class HomeContactsListHelper { @In(create=true) EntityManager entityManager; @In(required = true) Contact loggedUser; private List<Contact> contactsList; public List<Contact> getContactsList() { if (contactsList ==null) { // Creating the query String query="from Contact c where c.contact.id=:fatherId"; // Getting the contacts list contactsList = (List<Contact>) entityManager.createQuery(query) .setParameter("fatherId", loggedUser.getId()) .getResultList(); } return contactsList; } public void setContactsList(List<Contact> contactsList) { this.contactsList = contactsList; }

Para resumir, la anotación @Name define el nombre del componente Seam / JSF del bean de respaldo, @Scope define el alcance del componente, se inyecta (con la anotación @In), el componente entityManager (para consultar la base de datos con JPA) y la instancia de contacto referenciando al usuario conectado durante la fase de inicio de sesión. Además, el bean tiene una propiedad llamada contactsList que es lentamente inicializado en el método getContactsList() consultando la base de datos. Como estamos utilizando el ámbito de la conversación, nos gustaría iniciar la conversación para entrar en la página de inicio. Hay diferentes maneras de hacer esto en nuestro caso, vamos a abrir el archivo /view/home.page.xml y agregamos el siguiente contenido:

<begin-conversation join="true" /> Así que, ahora, cuando el usuario acceda a la página de inicio, una nueva conversación se crea si no hay ninguno. Si no, la existente se mantendrá (join = "true").

Page 13: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Los detalles del contacto Para la tercera columna, nos gustaría mostrar tres estados diferentes: El mensaje "contacto no seleccionado" cuando no se ha seleccionado ningún contacto (para que la propiedad sea null). Una vista de la caja sólo cuando no estamos en el modo de edición (la propiedad selectedContactEditing se establece en false) Un cuadro de edición cuando estamos en el modo de edición (la propiedad selectedContactEditing se establece a true) Por lo tanto, vamos a abrir la página home.xhtml e insertaremos la tercera columna dentro de la cuadricula del panel con los tres estados:

<a:outputPanel id="contactDetail"> <a:outputPanel rendered="#{homeSelectedContactHelper. selectedContact==null}"> <rich:panel> <h:outputText value="#{messages['noContactSelected']}"/> </rich:panel> </a:outputPanel> <a:outputPanel rendered="#{homeSelectedContactHelper. selectedContact!=null and homeSelectedContactHelper. selectedContactEditing==false}"> <ui:include src="main/contactView.xhtml"/> </a:outputPanel> <a:outputPanel rendered="#{homeSelectedContactHelper. selectedContact!=null and homeSelectedContactHelper. selectedContactEditing==true}"> <ui:include src="main/contactEdit.xhtml"/> </a:outputPanel> </a:outputPanel>

Aquí, hemos puesto la principal etiqueta a:outputPanel como el marcador de posición principal y dentro ponemos tres casos más de a:outputPanel (uno por cada estado) con el atributo presenta a fin de decidir cuál de ellas se va a mostrar. La primera de ellas sólo muestra un mensaje cuando se establece en null homeSelectedContactHelper. selectedContact:

La segunda instancia de a:outputPanel incluirá el archivo main/contactView.xhtml sólo si homeSelectedContactHelper.selectedContact no es null y no estamos en modo de edición (para homeSelectedContactHelper.selectedContactEditing se establece en false), la tercera sólo se mostrarán si

Page 14: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

homeSelectedContactHelper.selectedContact no es nulo, y estamos en el modo de edición (es decir homeSelectedContactHelper.selectedContactEditing es igual a true). Antes de empezar a escribir las secciones include, vamos a ver cómo el bean principal para el contacto seleccionado se vé y conectarlo con la tabla de datos para seleccionar el contacto de éste.

El bean de soporte Vamos a crear una nueva clase llamada HomeSelectedContactHelper dentro del paquete book.richfaces.advcm.modules.main, la clase puede ser algo como esto:

@Name("homeSelectedContactHelper") @Scope(ScopeType.CONVERSATION) public class HomeSelectedContactHelper { @In(create = true) EntityManager entityManager; @In(required = true) Contact loggedUser; @In FacesMessages facesMessages; // My code here }

Este es un componente estándar de JBoss Seam, como hemos visto en los otros capítulos y ahora vamos a añadir nuestras propiedades. El bean que vamos a utilizar para ver y editar las características es muy sencillo de entender ya que sólo contiene dos propiedades (es decir, selectedContact y selectedContactEditing) y algunos métodos de acción para su administración. Vamos a añadir las propiedades a nuestra clase:

private Contact selectedContact; private Boolean selectedContactEditing; public Contact getSelectedContact() { return selectedContact; } public void setSelectedContact(Contact selectedContact) { this.selectedContact = selectedContact; } public Boolean getSelectedContactEditing() { return selectedContactEditing; } public void setSelectedContactEditing(Boolean selectedContactEditing) { this.selectedContactEditing = selectedContactEditing; }

Como puede ver, simplemente hemos añadido dos propiedades con el estándar getter y setter. Vamos a ver ahora los métodos de acción:

public void createNewEmptyContactInstance() {

Page 15: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

setSelectedContact(new Contact()); } public void insertNewContact() { // Attaching the owner of the contact getSelectedContact().setContact(loggedUser); entityManager.persist(getSelectedContact()); facesMessages.addFromResourceBundle(StatusMessage.Severity.INFO, "contactAdded"); } public void saveContactData() { entityManager.merge(getSelectedContact()); facesMessages.addFromResourceBundle(StatusMessage.Severity.INFO, "contactSaved"); } public void deleteSelectedContact() { entityManager.remove(getSelectedContact()); // De-selecting the current contact setSelectedContact(null); setSelectedContactEditing(null); facesMessages.addFromResourceBundle(StatusMessage.Severity.INFO, "contactDeleted"); } public boolean isSelectedContactManaged() { return getSelectedContact() != null && entityManager.contains(getS electedContact()); }

No es difícil entender lo que hacen, sin embargo, con el fin de ser claros, vamos a describir lo que cada método hace. El método createNewEmptyContactInstance() simplemente establece la propiedad selectedContact con una nueva instancia de la clase de Contact será llamado por "Añadir contacto". Después de que el usuario ha hecho clic en "Añadir contacto" se incluirán los datos de contacto, él / ella ha de persistir esta nueva instancia de los datos en la base de datos. Se lleva a cabo por el insertNewContact () método, llamado cuando se hace clic en el botón Insertar. Si el usuario edita un contacto y haga clic en el botón "Guardar", el método saveContactData() será llamado, con el fin de almacenar las modificaciones en la base de datos. Al igual que al guardar, el método deleteSelectedContact ()será llamado por el botón "Eliminar", a fin de eliminar la instancia de la base de datos. Una mención especial para el método isSelectedContactManaged()que se utiliza para determinar si la propiedad selectedContact contiene un bean que existe en la base de datos (así, estoy editando), o una nueva instancia aún no persistió a la base de datos. Lo utilizamos sobre todo en propiedades rendered, a fin de determinar qué componente para mostrar (podrás ver esto en la sección siguiente).

Seleccionar el contacto en la lista de contactos Vamos a utilizar la lista de contactos a fin de decidir que el contacto se debe demostrar en la vista de detalle.

Page 16: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

La forma más sencilla es añadir una nueva columna en el DataTable, y poner un botón de comando (o enlace) para seleccionar el bean con el fin de visualizar la vista de detalle. Vamos a abrir el archivo contactsList.xhtml y añadir otra columna como sigue:

<rich:column width="10%" style="text-align: center"> <a:commandButton image="/img/view.png" reRender="contactDetail"> <f:setPropertyActionListener value="#{contact}" target="#{homeSelectedContactHelper.selectedContact}"/> <f:setPropertyActionListener value="#{false}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> </a:commandButton> </rich:column>

Dentro de la columna, hemos añadido el compponente a:commandButton (que muestra una imagen en lugar del texto estándar) que no requiere ninguna acción que utiliza el método f:setPropertyAction para establecer el valor homeSelectedContactHelper.selectedContact a el contacto con (el valor de fila de la DataTable), y para decirle que muestre el cuadro de vista y no la edición (configuración homeSelectedContactHelper.selectedContactEditing a false). Después de la llamada Ajax, se volverá a hacer el cuadro de contactDetail con el fin de reflejar el cambio. Además, el encabezado debe ser cambiado para reflejar la columna de añadir:

<rich:dataTable ... > <f:facet name="header"> <rich:columnGroup> <rich:column colspan="3"> <h:outputText value="Contacts"/> </rich:column> <rich:column breakBefore="true"> <h:outputText value="Name"/> </rich:column> <rich:column> <h:outputText value="Surname"/> </rich:column> <rich:column>

<rich:spacer/> </rich:column> </rich:columnGroup> </f:facet> ...

Hemos incrementado el valor del atributo colspan y se agregó una nuevo encabezado (vació) de la columna. La nueva lista de contactos se parecerá a la siguiente pantalla:

Page 17: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Añadir un nuevo contacto Otra característica que nos gustaría añadir a la lista de contactos es el "Añadir contacto". Con el fin de hacer eso, vamos a usar la barra de herramientas vacía que ponemos en la primera sección de este capítulo. Vamos a añadir un botón de acción en el componente rich:toolBar:

<a:commandButton image="/img/addcontact.png" reRender="contactDetail" action="#{homeSelectedContactHelper.createNewEmptyContactInstance}"> <f:setPropertyActionListener value="#{true}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> </a:commandButton>

Este botón se llame al método de acción homeSelectedContactHelper.createNewEmptyContactInstance() a fin de crear y seleccionar una instancia vacía y establecerá homeSelectedContactHelper.selectedContactEditing a true con el fin de iniciar la edición, después de las llamadas Ajax, se volverá a reconstruir el cuadro de contactDetail para reflejar los cambios.

Ver los detalles del contacto Estamos dispuestos a poner en práctica la opinión de cuadro de contacto detalle, simplemente abra el archivo /view/main/contactView.xhtml y agregue el siguiente código:

<h:form> <rich:panel> <f:facet name="header"> <h:outputText value="#{homeSelectedContactHelper.selectedContact.name} #{homeSelectedContactHelper.selectedContact.surname}"/> </f:facet> <h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value">

Page 18: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

<h:outputText value="#{messages['name']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.name}"/> <h:outputText value="#{messages['surname']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.surname}"/> <h:outputText value="#{messages['company']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.company}"/> <h:outputText value="#{messages['email']}:"/> <h:outputText value="#{homeSelectedContactHelper.selectedContact.email}"/> </h:panelGrid> </rich:panel> <rich:toolBar> <rich:toolBarGroup> <a:commandLink ajaxSingle="true" reRender="contactDetail" styleClass="image-command-link"> <f:setPropertyActionListener value="#{true}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> <h:graphicImage value="/img/edit.png" /> <h:outputText value="#{messages['edit']}" /> </a:commandLink> </rich:toolBarGroup> </rich:toolBar> </h:form>

La primera parte es el componente rich:panel que contiene a h:panelGrid con el detalle de los campos. En la segunda parte del código, colocamos un rich:toolBar que contiene el enlace de comandos (con una imagen y un texto) que activa el modo de edición, que de hecho, sólo se establece la propiedad homeSelectedContactHelper.selectedContactEditing a true y vuelve a reconstruir contactDetail con el fin de hacer que aparezca en el cuadro de edición. También hemos añadido una clase CSS dentro del archivo /view/stylesheet/theme.css para manejar el diseño de los enlaces de comandos con las imágenes:

.image-command-link { text-decoration: none; } .image-command-link img { vertical-align: middle; padding-right: 3px; }

La vista del cuadro es:

Page 19: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Ahora estamos listos para desarrollar el cuadro de edición.

Edición de los detalles del contacto Cuando en el modo de edición, el contenido de la vista /view/main/contactEdit.xhtml se muestra en el cuadro de detalles de contacto, vamos a abrirlo para editarlo. Vamos a añadir el código para crear el panel principal:

<h:form> <rich:panel> <f:facet name="header"> <h:panelGroup> <h:outputText value="#{homeSelectedContactHelper.selectedContact.name} #{homeSelectedContactHelper.selectedContact.surname}" rendered="#{homeSelectedContactHelper.selectedContactManaged}"/> <h:outputText value="#{messages['newContact']}" rendered="#{!homeSelectedContactHelper.selectedContactManaged}"/> </h:panelGroup> </f:facet> <!-- my code here --> </rich:panel> <!-- my code here --> </h:form>

Este es un panel estándar rich:panel con un encabezado personalizado que tiene dos componentes h:outputText que se mostrará en función del atributo (si se trata de un nuevo contacto o no). Más de un componente dentro de f:facet Recuerde que f:facet debe tener un solo hijo, por lo que, para poner más de un componente, tienes que usar un h:panelGroup o algo similar. En el interior del panel, se van a poner h:panelGrid contiene los componentes para la edición de datos:

<rich:graphValidator> <h:panelGrid columns="3" rowClasses="prop" columnClasses="name,value,validatormsg"> <h:outputLabel for="scName" value="#{messages['name']}:"/> <h:inputText id="scName" value="#{homeSelectedContactHelper.selectedContact.name}"/> <rich:message for="scName" styleClass="messagesingle"

Page 20: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> <h:outputLabel for="scSurname" value="#{messages['surname']}:"/> <h:inputText id="scSurname" value="#{homeSelectedContactHelper.selectedContact.surname}"/> <rich:message for="scSurname" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> <h:outputLabel for="scCompany" value="#{messages['company']}:"/> <h:inputText id="scCompany" value="#{homeSelectedContactHelper.selectedContact.company}"/> <rich:message for="scCompany" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> <h:outputLabel for="scEmail" value="#{messages['email']}:"/> <h:inputText id="scEmail" value="#{homeSelectedContactHelper.selectedContact.email}"/> <rich:message for="scEmail" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGrid> <rich:graphValidator>

Nada complicado aquí, acabamos de utilizar h:outputLabel, h:inputText y rich:message para todos los propiedades de Contact para ser editado, que aparece como sigue:

El botón de la barra de herramientas Al final del panel, nos gustaría poner la barra de herramientas contiene los botones de acción para la inserción, guardar, cancelar y eliminar el contacto seleccionado que se muestra. Con el fin de hacer eso, vamos a insertar el código siguiente después de las etiquetas de cierre rich:panel (y antes de la etiqueta de cierre h:form):

<rich:toolBar> <rich:toolBarGroup> <!-- my action buttons here -->

Page 21: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

</rich:toolBarGroup> </rich:toolBar> Empecemos por la inserción de los botones de acción para introducir un nuevo contacto:

<a:commandLink reRender="contactsList,contactDetail" action="#{homeSelectedContactHelper.insertNewContact}" rendered="#{!homeSelectedCon tactHelper.selectedContactManaged}" styleClass="image-command-link"> <f:setPropertyActionListener value="#{null}" target="#{homeContactsListHelper.contactsList}"/> <h:graphicImage value="/img/insert.png"/> <h:outputText value="#{messages['insert']}"/> </a:commandLink>

Este botón persiste el nuevo contacto en la base de datos (llamando al método homeSelectedContactHelper.insertNewContact()) y, con la propiedad f:setPropertyActionListener, se establece la propiedad contactsList en null, lo que la lista se leerá de nuevo desde la base de datos (para que refleje los cambios). Después de eso, se vuelve a hacer la lista y el cuadro de detalle para reflejar los cambios. Veamos el código del botón para cancelar la inserción:

<a:commandLink ajaxSingle="true" reRender="contactDetail" rendered="#{!homeSelectedContactHelper. selectedContactManaged}" styleClass="image-command-link"> <f:setPropertyActionListener value="#{false}" target="#{homeSelectedContactHelper. selectedContactEditing}"/> <f:setPropertyActionListener value="#{null}" target="#{homeSelectedContactHelper. selectedContact}"/> <h:graphicImage value="/img/cancel.png"/> <h:outputText value="#{messages['cancel']}"/> </a:commandLink>

Este botón no llama a cualquier método de acción, sino que sólo establece la propiedad selectedContact a null y la propiedad selectedContactEditing a false para "cancelar" la acción de inserción. Destacamos la propiedad ajaxSingle, esta es una característica muy importantes que se utilizan para evitar el envío del formulario cuando se pulsa el botón (así, en este caso, cuando el usuario hace clic en el botón Cancelar, los datos del formulario no se haya presentado con la solicitud de Ajax) . Lo veremos más a fondo en la final de la sección. El otro botón que vamos a añadir es el botón Guardar:

<a:commandLink reRender="contactsList,contactDetail" action="#{homeSelectedContactHelper.saveContactData}" rendered="#{homeSelectedContactHelper.selectedContactManaged}" styleClass="image-command-link"> <f:setPropertyActionListener value="#{false}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> <f:setPropertyActionListener value="#{null}" target="#{homeContactsListHelper.contactsList}"/>

Page 22: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

<h:graphicImage value="/img/save.png"/> <h:outputText value="#{messages['save']}"/> </a:commandLink>

Simplemente guarda la modificación de la propiedad, se establece la propiedad lista de contactos a null, (así, se leerá de nuevo desde la base de datos), y establece el modo de edición en false (así, los detalles de contacto se muestra). El botón Cancelar de un contacto existente es casi el mismo que el de los nuevos contactos:

<a:commandLink ajaxSingle="true" reRender="contactDetail" rendered="#{homeSelectedContactHelper.selectedContactManaged}" styleClass="image-command-link"> <f:setPropertyActionListener value="#{false}" target="#{homeSelectedContactHelper.selectedContactEditing}"/> <h:graphicImage value="/img/cancel.png"/> <h:outputText value="#{messages['cancel']}"/> </a:commandLink>

La única diferencia es que no establece el selectedContact a null como nos gustaría ver el contacto en el modo de vista después de cancelar la edición. El último botón que vamos a introducir es la de la eliminación:

<a:commandLink ajaxSingle="true" reRender="contactDetail,contactsList" action="#{homeSelectedContactHelper.deleteSelectedContact}" rendered="#{homeSelectedContactHelper.selectedContactManaged}" styleClass="image-command-link"> <f:setPropertyActionListener value="#{null}" target="#{homeContactsListHelper.contactsList}"/> <h:graphicImage value="/img/delete.png"/> <h:outputText value="#{messages['delete']}"/> </a:commandLink>

Llama a el método homeSelectedContactHelper.deleteSelectedContact() que establece en null a selectedContact y el selectedContactEditing (es una manera diferente de hacer lo que hemos hecho para los botones de acción de otros utilizando comoponentes f:setPropertyListener). A continuación, establece en null la propiedad de contactos y reconstruye los cuadros contactList y contactDetail. Aquí hay una captura de pantalla del cuadro de edición con la barra de herramientas:

Page 23: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Los atributos ajaxSingle y process La propiedad ajaxSingle es muy útil para controlar el envío del formulario cuando ajaxSingle se establece en true, el formulario no se envía sólo los datos de los componentes Ajax. Este atributo se encuentra disponible en todos los componentes de acción Ajax y podemos usarlo para llamar a una acción de un botón, saltar la validación de formularios (como la propiedad immediate de JSF), o para enviar el valor de entrada de sólo una en una forma sin la validación y la la presentación de los otros. El segundo caso de uso puede ser utilizado, por ejemplo, cuando necesitamos un menú de entrada que cambia dinámicamente el valor de otras entradas, sin presentar el formulario completo:

<h:form> <!-- other input controls --> <h:selectOneMenu id="country" value="#{myBean.selectedCountry}"> <f:selectItems value="#{myBean.myCountries}"> <a:support event="onchange" ajaxSingle="true" reRender="city" /> </h:selectOneMenu> <h:selectOneMenu id="city" value="#{myBean.selectedCity}"> <f:selectItems value="#{myBean.myCities}"> </h:selectOneMenu> <!-- other input controls --> </h:form>

En este ejemplo, cada vez que el usuario selecciona un país nuevo, el valor es envíado al bean que vuelve a calcular la propiedad myCities para el nuevo país, después de que el menú de la ciudad se vuelven a representar para mostrar las nuevas ciudades. Todo lo que no se envía del formulario o se bloquean los cambios a causa de algún problema de validación. ¿Qué pasa si usted desea enviar más de un valor, pero todavía no todo el formulario? Podemos utilizar las regiones Ajax (que veremos en las siguientes secciones), o podemos usar el atributo process. Este contiene una lista de componentes para el proceso, mientras que se envía la acción Ajax:

<h:form> <!-- other input controls --> <h:inputText id="input1" ... /> <h:selectOneMenu id="country" value="#{myBean.selectedCountry}"> <f:selectItems value="#{myBean.myCountries}"> <a:support event="onchange" ajaxSingle="true" process="input2, input3" reRender="city" /> </h:selectOneMenu> <h:inputText id="input2" ... /> <h:inputText id="input3" ... /> <h:selectOneMenu id="city"

Page 24: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

value="#{myBean.selectedCity}"> <f:selectItems value="#{myBean.myCities}"> </h:selectOneMenu> <!-- other input controls --> </h:form>

En este ejemplo, también queríamos presentar los valores input2 y input3, junto con el nuevo país, porque son útiles para la recuperación de la nueva lista de las ciudades, simplemente estableciendo el atributo process con la lista de identificación y durante la presentación, se procesarán. Así input1 no se enviará. Además, para los componentes de acción, tales como botones, puede decidir qué enviar utilizando los atributos ajaxSingle y process.

Formulario de presentación y procesamiento Hablamos acerca de la forma "presentación" para simplificar el concepto y hacer las cosas más comprensibles. En realidad, para cada petición, todos los formularios son enviados, pero sólo los componentes seleccionados (con ajaxSingle y / o atributos process) serán "transformados". Por "transformados" nos referimos a "pasar a través de" las fases de JSF (decodificación, conversión, validación y el modelo de actualización).

Más Ajax Por cada contacto, nos gustaría añadir más campos personalizables, así que vamos a utilizar la entidad ContactField conectado a todas las instancias de Contact. En primer lugar, vamos a crear un bean de soporte llamado HomeSelectedContactOtherFieldsHelper dentro del paquete book.richfaces.advcm.modules.main Puede verse así:

@Name("homeSelectedContactOtherFieldsHelper") @Scope(ScopeType.CONVERSATION) public class HomeSelectedContactOtherFieldsHelper { @In(create = true) EntityManager entityManager; @In(required = true) Contact loggedUser; @In FacesMessages facesMessa @In(required = true)

ges;

HomeSelectedContactHelper homeSelectedContactHelper; // my code }

Algo notable que se resalta es el componente homeSelectedContactHelper, porque para obtener la lista de los campos personalizados de la base de datos, necesitamos el propio contacto. También se establece el atributo required en true, ya que este bean no puede existir sin el contexto homeSelectedContactHelper. Ahora, vamos a añadir la propiedad que contiene la lista de campos personalizados para los contactos seleccionados:

Page 25: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

private List<ContactField> contactFieldsList; public List<ContactField> getContactFieldsList() { if (contactFieldsList == null) { // Getting the list of all the contact fields String query = "from ContactField cf where cf.contact.id=: idContactOwner order by cf.id"; contactFieldsList = (List<ContactField>) entityManager.createQuery(query) .setParameter("idContactOwner", homeSelectedContactHelper.getSelectedContact() .getId()).getResultList(); } return contactFieldsList; } public void setContactFieldsList(List<ContactField> contactFieldsList) { this.contactFieldsList = contactFieldsList; }

Como puede ver, es una característica normal inicializarlo usando el método de acceso. Esta consulta la base de datos para recuperar la lista de campos personalizados para el contacto seleccionado. Tenemos que poner en el bean de algún otro método útil para administrar el campo personalizado (adición y eliminación de campo y de la base de datos), vamos a añadir los métodos:

public void createNewContactFieldInstance() { // Adding the new instance as last field (for inserting a new field) getContactFieldsList().add(new ContactField()); } public void persistNewContactField(ContactField field) { // Attaching the owner of the contact field.setContact(homeSelectedContactHelper.getSelectedContact()); entityManager.persist(field); } public void deleteContactField(ContactField field) { // If it is in the database, delete it if (isContactFieldManaged(field)) { entityManager.remove(field); } // Removing the field from the list getContactFieldsList().remove(field); } public boolean isContactFieldManaged(ContactField field) { return field != null && entityManager.contains(field); }

El método createNewContactFieldInstance()sólo añadirá una nueva (aún persiste), instancia vacía de la clase ContactField en la lista. Después de que el usuario ha rellenado los valores, él / ella presiona un botón que llama al método persistNewContactField () para guardar los nuevos datos en la base de datos. Para eliminar, vamos a utilizar el método deleteContactField () y para determinar si una instancia persiste en la base de datos o no, vamos a utilizar el método isContactFieldManaged().

Page 26: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Ahora, vamos a abrir el archivo /view/main/contactView.xhtml y vamos a agregar el código que mostrará los campos personalizados después de h:panelGrid:

<a:repeat value="#{homeSelectedContactOtherFieldsHelper. contactFieldsList}" var="field"> <h:panelGrid columns="2" rowClasses="prop" columnClasses="name,value"> <h:outputText value="#{field.type} (#{field.label}):"/> <h:outputText value="#{field.value}"/> </h:panelGrid> </a:repeat>

Estamos utilizando un nuevo componente de iteración de datos RichFaces que nos permite iterar sobre una colección y poner los datos que queremos (el componente rich:dataTable crea una tabla con la lista de elementos). En nuestro caso, el bloque h:panelGrid se repetirá para cada uno de los elementos de la colección (para cada campo personalizado). Ahora, vamos a abrir archivo /view/main/contactEdit.xhtml y agregue el código para editar los campos personalizados en la lista:

<a:region> <a:outputPanel id="otherFieldsList"> <a:repeat value="#{homeSelectedContactOtherFieldsHelper. contactFieldsList}" var="field"> <h:panelGrid columns="3" rowClasses="prop" columnClasses="name,value,validatormsg"> <h:panelGroup> <h:inputText id="scOtherFieldType" value="#{field.type}" required="true" size="5"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText> <h:outputText value=" ("/> <h:inputText id="scOtherFieldLabel" value="#{field.label}" size="5"> <a:support event="onblur" ajaxSingle="true"/> </h:inputText> <h:outputText value=")"/><br/> <rich:message for="scOtherFieldType" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGroup> <h:panelGroup> <h:inputText id="scOtherFieldValue" value="#{field.value}" required="true"> <a:support event="onblur" ajaxSingle="true"/>

Page 27: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

</h:inputText><br/> <rich:message for="scOtherFieldValue" styleClass="messagesingle" errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"/> </h:panelGroup> <h:panelGroup> <a:commandButton image="/img/add.png" reRender="otherFieldsList" action="#{homeSelectedContactOtherFieldsHelper. persistNewContactField(field)}" rendered="#{!homeSelectedContactOtherFieldsHelper. isContactFieldManaged(field)}"> </a:commandButton> <a:commandButton image="/img/remove.png" reRender="otherFieldsList" ajaxSingle="true" action="#{homeSelectedContactOtherFieldsHelper. deleteContactField(field)}"> </a:commandButton> </h:panelGroup> </h:panelGrid> </a:repeat> <a:commandLink reRender="otherFieldsList" ajaxSingle="true" action="#{homeSelectedContactOtherFieldsHelper. createNewContactFieldInstance}" rendered="#{homeSelectedContactHelper. selectedContactManaged}" styleClass="image-command-link"> <h:graphicImage value="/img/add.png"/> <h:outputText value="#{messages['addNewField']}"/> </a:commandLink> </a:outputP</a:region>

anel>

El código es muy similar a la del cuadro de vista, excepto por los botones de acción (para añadir una nueva instancia, persistencia, guardar o eliminar) y, por la presencia de la etiqueta que rodea a:region (resaltado). Esto es muy importante para asegurarse de que la forma funciona correctamente, vamos a ver por qué en la siguiente sección. También observe que todos los componentes de entrada tiene la etiqueta a:support como un hijo que va a actualizar el bean editando el valor en el evento onblur (lo que significa que cada vez que cambia el foco a otro componente, el valor de la última es enviado). Así que, si elimina o añade un campo, ahora se perderán los valores editados en otros campos. También se utiliza para la validación del Ajax, y el usuario es informado de que el valor no es válido cuando se mueve el cursor a otra entrada. Aquí hay una captura de pantalla con la nueva característica en el cuadro de edición:

Page 28: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Usando a:support para la validación de Ajax Si desea utilizar la a:support únicamente para fines de validación, recuerde poner el atributo bypassUpdates en true, por lo que el proceso sería más rápido que el modelo de actualización de JSF y las fases de invocación de la aplicación no serán invocadas.

Contenedores Ajax Durante el desarrollo de una aplicación web con RichFaces, es muy útil saber cómo utilizar los contenedores Ajax (como el comoponente a:region) a fin de optimizar las peticiones Ajax. En esta sección, vamos a discutir sobre el componente a:region. Es un componente muy importante del marco de trabajo, ya que puede definir las áreas Ajax para limitar la parte del árbol de componentes que serán procesados en una petición Ajax. Las regiones se pueden anidar en una petición Ajax y el más cercano será utilizado. Al establecer a true el atributo a:region llamado regionRenderOnly, puede utilizar este componente para limitar la actualización de los elementos, de este modo, de hecho, sólo los componentes dentro de la región se pueden actualizar. Otro atributo importante es selfRendered, estableciendo ésta a true indica el marco para crear la respuesta basándose en el árbol de componentes sin hacer referencia al código de la página, es más rápido, pero todos los elementos transitorios que no se guardan en el árbol (como f:verbatim ó código HTML escrita directamente sin necesidad de utilizar componentes JSF) se perderán la primera vez de refrescado, por lo que no se pueden utilizar en este caso. En resumen, es muy útil para controlar el proceso de representación y optimizar, con el fin de limitar los elementos de un formulario para enviar durante una petición Ajax sin problemas de validación, para mostrar los diferentes indicadores de la condición Ajax. Ejemplo del uso de a:region:

Page 29: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

<h:form> <a:region> <h:inputText id="it1" value="#{aBean.text1}"> <a:support event="onkeyup" reRender="text1" /> </h:inputText> <h:inputText id="it2" value="#{aBean.text2}" /> </a:region> <h:inputText id="it3" value="#{aBean.text3}" /> <a:commandButton action="#{aBean.saveTexts}" reRender="text1,text2" /> </h:form> <h:outputText id="text1" value="#{aBean.text1}" /> <h:outputText id="text2" value="#{aBean.text2}" />

En este ejemplo, mientras el usuario está escribiendo en el valor del text1 de inputText, a:support envía una petición Ajax que contiene sólo los valores it1 y it2 de inputText. En este caso, de hecho, a:region limíta los componentes enviados por cada petición Ajax se originó en el interior de la región. Por lo tanto, la petición Ajax sólo se actualizará aBean.text1 y aBean.text2. Envolver sólo un componente dentro de una región del Ajax es el equivalente de usar la propiedad ajaxSingle establecida a true. Si el usuario hace clic en el control a:commandButton aBean.text1, los valores aBean.text2 y aBean.text3 serán actualizados por la petición Ajax. Volviendo a nuestra aplicación, como todos los campos personalizados dentro del mismo componente de formulario, nos rodean cada uno de ellos con la etiqueta a:region. De esta manera, el campo simplemente se presenta, independientemente de los demás. Por ejemplo, sin utilizar a:region, si el usuario se vacía el valor de entrada del nombre y luego trata de insertar un campo personalizado nuevo, el proceso fallará porque el nombre de entrada no está validado. Si usamos el componente a:region, el campo de nombre no será procesada y un nuevo campo será insertado. Ahora que sabemos cómo utilizar la etiqueta a:region, podemos combinarlo con ajaxSingle y process para decidir qué enviar en cada solicitud y para optimizar mejor las interacciones Ajax en la aplicación.

Iteración de datos usando RichFaces Todos los componentes de datos de iteración RichFaces comparten el mismo modo de trabajo del estándar h:dataTable. Así que, una vez que sabe cómo usarlo, será capaz de utilizar todos ellos sin ningún problema. Echemos un vistazo de nuevo en una versión simple de los rich:dataTable que hemos utilizado para la lista de contactos:

<rich:dataTable value="#{homeContactsListHelper.contactsList}"

var="contact"> <rich:column>

<h:outputText value="#{contact.name}"/> </rich:column> <rich:column> <h:outputText value="#{contact.surname}"/>

Page 30: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

</rich:column> </rich:dataTable>

El resultado de este código es simplemente previsible una tabla con dos columnas, una para el nombre y el otro para el apellido. Ahora, supongamos que no quiero que el formato de tabla, sino una lista de contactos, lo único que tienes que hacer es utilizar el componente rich:dataList la misma forma que rich:dataTable:

<rich:dataList value="#{homeContactsListHelper.contactsList}" var="contact"> <h:outputText value="#{contact.name} #{contact.surname}"/>

</rich:dataList> Para cada elemento, se hará una lista de contactos de la siguiente manera:

Exactamente el mismo mecanismo que le permite utilizar componentes rich:dataOrderingList y rich:dataDefinitionList. Una mención especial para los rich:dataGrid que tiene algunas diferencias:

<rich:dataGrid value="#{homeContactsListHelper.contactsList}" var="contact"columns="3">

<h:outputText value="#{contact.name} #{contact.surname}"/>

</rich:dataGrid> Como puede ver, hemos tenido que poner el atributo columns para saber cuándo termina la fila y empieza una nueva. Aquí está el resultado:

Usted puede colocar cualquier componente que desee en su interior:

<rich:dataGrid value="#{homeContactsListHelper.contactsList}" var="contact" columns="3"> <rich:panel> <f:facet name="header">

<h:outputText value="Contact" /> </f:facet> <h:outputText

value="#{contact.name} #{contact.surname}"/> </rich:panel> </rich:dataGrid>

Y el resultado es:

Page 31: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Paginación de datos con los componentes de la iteración de datos En cuanto a h:dataTable (y rich:dataTable), puede adjuntar datascroller a cada componente de iteración de datos de la misma forma que lo hizo con su DataTable:

<h:form> <rich:dataList id="contactsList"

value="#{homeContactsListHelper.contactsList}" var="contact

rows="3"> "

<h:outputText value="#{contact.name} #{contact.surname}"/> </rich:dataList> <rich:datascroller for="contactsList" />

</h:form> Sólo recuerde colocar datascroller denttro de form, el atributo set, y establecer el atributo de rows para uno de los componentes de iteración de datos. El resultado es el siguiente:

Además, en este caso, existe una pequeña excepción para el componente rich:dataGrid, ya que no tiene el atributo rows, pero el correspondiente es elements (se puede averiguar por qué). Por lo tanto, nuestro ejemplo será:

<h:form> <rich:dataGrid id="contactsGrid"

value="#{homeContactsListHelper.contactsList}" var="contact"

columns="3" elements="3"> <rich:panel>

<f:facet name="header"> <h:outputText value="Contact" />

</f:facet> <h:outputText value="#{contact.name} #{contact.surname}"/> </rich:panel>

</rich:dataGrid> <rich:datascroller for="contactsGrid" />

</h:form>

Page 32: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Y el resultado sería el siguiente:

Administración de direcciones Otra pieza que nos gustaría hacer es la administración de direcciones, utilizando la entidad ContactAddress. Este es el mismo mecanismo de trabajo que en el campo personalizado, por lo que se deja como ejercicio para el lector. Sin embargo, usted puede encontrar la función desarrollada en el código fuente de la aplicación.

Algunas capturas de pantalla Aquí, presentamos algunas capturas de pantalla de la aplicación con todas las características que hemos visto hasta ahora. Podemos ver la lista de contactos con un contacto seleccionado:

El formulario de edición de contacto (se nota en los botones para agregar / eliminar más campos y direcciones) aparece como sigue:

Page 33: JBoss Richfaces. Capítulo 6. Creación de la lista de contactos con sus detalles

Y finalmente tu puedes ver y agregar el formulario de contactos:

Resumen En este capítulo, hemos desarrollado la característica principal de nuestra aplicación de administración de contactos. Hemos aprendido sobre la interacción del Ajax y los contenedores y sobre los nuevos componentes que Ajax RichFaces ofrece. En el próximo capítulo, vamos a desarrollar nuevas funciones para el Administrador de contactos Avanzado y el descubriremos los nuevos componentes y patrones RichFaces.