— PEDRO DELGADO YARZA 2014/01/29 13:48
Versión: 4.0.7
En esta sección vamos a exponer los componentes primefaces recomendados desde MNCS para desarrollar las aplicaciones Fundeweb 2.0. En caso de querer consultar el listado completo de los componentes primefaces disponibles, podéis visitar su página de demostración en la url http://www.primefaces.org/showcase/ui/home.jsf
Es importante destacar que la versión de primefaces que contiene esa página de demo no está disponible aún para los desarrolladores, por lo que algún componente puede comportarse de manera ligeramente diferente a la vista en la demo. Los componentes sujetos a cambios en la versión están sombreados en el menú de demostración de primefaces.
Los componentes básicos o con una explicación suficiente en la demo de primefaces aparecen únicamente referenciados en esta guía. Los que hemos encontrado algo más complejos, novedosos, o que requieren un comportamiento especial han sido analizados. Estos análisis se pueden ampliar en base a las necesidades que surjan durante los desarrollos.
http://www.primefaces.org/showcase/ui/autocompleteHome.jsf
Este componente es una variante del componente InputText que filtra en el modelo los valores que concuerden con los caracteres introducidos en el filtro. Se puede permitir que se introduzcan valores no existentes en el filtro o impedirlo (según se desee).
Las propiedades a destacar son las siguientes:
Un ejemplo del código html
<p:autoComplete value="#{manejadorComponentesInput.provinciaSeleccionada}" id="autocompletePojo" completeMethod="#{manejadorComponentesInput.autocompleteProvincia}" var="provincia" itemLabel="#{provincia.proNombre}" itemValue="#{provincia}" converter="conversorProvincias" forceSelection="true" />
En este caso hemos mapeado directamente los datos a POJOs por lo que el código del conversor quedaría de la siguiente manera:
@FacesConverter(value = "conversorProvincias", forClass = Provincias.class) @RequestScoped public class ConversorProvincias implements Converter { private static final Logger log = Logger .getLogger(ConversorProvincias.class); //BeanManager necesario para recuperar los beans que hay cargados en el servidor //es el equivalente el Component.getInstance private BeanManager bm; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { ResourcesUtil ru = null; try { bm = (BeanManager) InitialContext.doLookup("java:comp/BeanManager"); //Recuperamos un bean de utilidad que contiene al entityManager que necesitamos //para realizar la búsqueda for (Bean b : bm.getBeans(ResourcesUtil.class)) { ru = (ResourcesUtil) bm.getReference(b, ResourcesUtil.class, bm.createCreationalContext(b)); } } catch (NamingException e) { log.error("Error obteniendo entityManager", e); } if (!UtilString.esCadenaVacia(value)) { Query consulta = ru.getEm().createNamedQuery("obtenerProvinciasId"); consulta.setParameter("codigo", value); return consulta.getSingleResult(); } else { return null; } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { if (value != null) { return ((Provincias) value).getProCodigo(); } else { return ""; } } }
Por último el código del método que devuelve la lista de opciones en base a los datos introducidos:
public List<Provincias> autocompleteProvincia(String query) { List<Provincias> provincias = new ArrayList<Provincias>(); Query consulta = em.createNamedQuery("obtenerProvinciasLike"); consulta.setParameter("filtro",query.toUpperCase()+"%"); provincias = consulta.getResultList(); return provincias; }
http://www.primefaces.org/showcase/ui/calendarAjax.jsf
Componente simple de selección de fecha, que o bien puede mostrarse al hacer click sobre el campo de texto asociado, o bien mediante un botón. Dentro de las características principales podemos destacar las siguientes:
Importante: Fundeweb ya incluye las librerias necesarias para el locale en castellano, no obstante si se quiere añadir otro idioma diferente del inglés o el español, o bien para aplicaciones no Fundeweb, es necesario, aparte de especificar el locale al componente, añadir en el directorio de recursos un fichero de nombre “calendar_(nombre del locale).js” (calendar_es.js para español). Un ejemplo del contenido de ese fichero (en español) es el siguiente:
PrimeFaces.locales['es'] = { closeText: 'Cerrar', prevText: 'Anterior', nextText: 'Siguiente', monthNames: ['Enero','Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], monthNamesShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun','Jul','Ago','Sep','Oct','Nov','Dic'], dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], dayNamesShort: ['Dom','Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'], dayNamesMin: ['D','L','M','X','J','V','S'], weekHeader: 'Semana', firstDay: 1, isRTL: false, showMonthAfterYear: false, yearSuffix: '', timeOnlyTitle: 'Sólo hora', timeText: 'Tiempo', hourText: 'Hora', minuteText: 'Minuto', secondText: 'Segundo', currentText: 'Fecha actual', ampm: false, month: 'Mes', week: 'Semana', day: 'Día', allDayText : 'Todo el día' }
Un ejemplo del código del componente sería el siguiente:
<p:calendar id="fechaAnuncio" pattern="dd/MM/yyyy" value="#{manejadorAnuncios.anuncioSeleccionado.fechaPublicacion}" locale="es" />
http://www.primefaces.org/showcase/ui/editor.jsf
Editor de texto enriquecido con barra de opciones configurable mediante la propiedad “controls”. El contenido del editor se guarda en formato html utilizando los caracteres de escape para los signos reservados. Las posibles opciones de configuración de la propiedad “controls” se especifican una a una separas por espacios.
Estas opciones son las siguientes: bold, italic, underline, strikethrough, subscript, superscript, font, size, style, color, highlight, removeformat, bullets, numbering, outdent, indent alignleft, center, alignright, justify, undo, redo, rule, image, link, unlink, cut, copy, paste, pastetext, print, source (muestra el codigo html que se va generando)
Un ejemplo de código sería el siguiente:
<p:editor id="editAnuncio" width="600" controls="bold italic underline strikethrough size font bullets numbering" rendered="#{manejadorAnuncios.modoEdicion}" value="#{manejadorAnuncios.anuncioSeleccionado.descripcion}" readonly="#{manejadorAnuncios.modoEdicion}" />
http://www.primefaces.org/showcase/ui/fileUploadMultiple.jsf
Componente de subida de ficheros. Permite subir múltiples ficheros y limitar tanto el tamaño y tipo de los mismos, como la cantidad máxima de ficheros a subir. Podemos hacer uso de dos casos, el simple que utiliza características del navegador y presenta una funcionalidad más recortada, o el avanzado que amplia las funcionalidades del componente, modifica el estilo visual y está basado en HTML5 (importante asegurar la compatibilidad del navegador).
Modo simple Este modo es parecido al que se puede simular por javascript. Recoge un fichero simple y lo sube al servidor tras hacer submit. Requiere, por tanto, un botón para ejecutar la acción que suba el documento.
<p:fileUpload value="#{manejadorFicheros.fichero}" mode="simple" /> <p:commandButton value="Submit" ajax="false" actionListener="#{manejadorFicheros.agregaFichero()}" />
Modo avanzado En este modo se nos permiten funcionalidades avanzadas como subir múltiples documentos a la vez usando ajax. Validaciones directas en el componente, visualización del listado de documentos, etc…
Las propiedades más relevantes son:
El componente por defecto limpia la lista de los ficheros que se han subido, en caso de querer mantenerla, de momento, se debe hacer mediante un componente a parte que se refresque con los nombres de los mismos.
El código de ejemplo es el siguiente:
<p:fileUpload fileUploadListener="#{manejadorComponentesInput.subidaFichero}" mode="advanced" dragDropSupport="true" multiple="true" update=":messages" sizeLimit="10000000" fileLimit="3" invalidFileMessage="#{messages['fileupload.invalid.type']}" invalidSizeMessage="#{messages['fileupload.invalid.size']}" fileLimitMessage="#{messages['fileupload.invalid.fileNumber']}" cancelLabel="#{messages['value.cancel']}" label="#{messages['fileupload.label.upload']}" auto="true" allowTypes="/(\.|\/)(pdf|gif|jpeg|png)$/" />
http://www.primefaces.org/showcase/ui/inputMask.jsf
Este componente nos permite asignar un patrón a un inputText de manera que los datos que introduzcamos se ajusten al patrón especificado.
Para completar la funcionalidad podemos añadir un validador de patrones para lanzar los posibles errores que pudiera ocasionar la inserción de los datos. La propiedad pattern nos permite indicar el patrón que tendrá el valor a introducir. Para ver más ejemplos de patrones, visitad el enlace del componente.
El código de ejemplo es el siguiente:
<div style="float: left;"> <p:outputLabel for="mask" value="Fecha manual " style="margin-right:10px;" styleClass="nombreLabel" /> <p:inputMask id="mask" value="#{manejadorComponentesInput.fecha}" mask="99/99/9999" required="true" validator="#{manejadorComponentesInput.validaFecha}" validatorMessage="#{messages['form.fecha.invalida']}"> <!-- Agregamos un validador para el patron de fecha --> <f:validateRegex pattern="[0-9]{2}/[0-1][0-9]/[0-9]{4}" for="mask" /> <!-- Rerenderizamos los mensajes de error cuando el componente pierde el foco --> <p:ajax update="iconoErrorFecha" event="blur" /> </p:inputMask> </div> <div style="float: left"> <!-- Muestra un icono de error junto al inputText --> <p:message for="mask" id="iconoErrorFecha" display="icon" showDetail="false" /> </div>
http://www.primefaces.org/showcase/ui/picklist.jsf
Este componente nos permite seleccionar un conjunto de elementos en una lista. Primefaces incorpora una clase Java DualListModel que permite especificar la lista origen y la lista destino. http://www.primefaces.org/docs/api/3.4/org/primefaces/model/DualListModel.html
Nota: Para ocultar los botontes añadir o eliminar todos hay que sobreescribir el css del botón:
.ui-picklist-button-add-all { visibility: hidden !important; } .ui-picklist-button-remove-all { visibility: hidden !important; }
El código del componente
<p:pickList id="provinciasPic" value="#{manejadorComponentesInput.provinciasPick}" var="provincia" itemValue="#{provincia}" itemLabel="#{provincia.proNombre}" converter="conversorProvincias"> <f:facet name="sourceCaption">Disponibles</f:facet> <f:facet name="targetCaption">Seleccionadas</f:facet> <p:ajax event="transfer" listener="#{manejadorComponentesInput.onTransfer}" /> </p:pickList>
Este componente nos provee de una agenda al estilo Outlook para anotar diferentes eventos. Permite crearlos, modificarlos y moverlos. Este componente debe estar controlado por un bean de tipo sesión.
Las propiedades más importantes son:
El componente tiene una serie de eventos que nos sirven para interactuar con él. Los más destacados son:
El código fuente es el siguiente:
<p:schedule id="agenda" value="#{agendaBean.agenda}" widgetVar="agendaWV" timeZone="GMT+1" allDaySlot="false" > <p:ajax event="dateSelect" listener="#{agendaBean.onDateSelect}" update="eventDetails" oncomplete="dialogoEvento.show()" /> <p:ajax event="eventSelect" listener="#{agendaBean.onEventSelect}" update="eventDetails" oncomplete="dialogoEvento.show()" /> <p:ajax event="eventMove" listener="#{agendaBean.onEventMove}" update=":messages" /> <p:ajax event="eventResize" listener="#{agendaBean.onEventResize}" update=":messages" /> </p:schedule> <p:dialog widgetVar="dialogoEvento" header="Event Details"showEffect="clip" hideEffect="clip"> <h:panelGrid id="eventDetails" columns="2"> <h:outputLabel for="title" value="#{messages['agenda.evento.nombre']}" /> <p:inputText id="title" value="#{agendaBean.eventoSeleccionado.title}" required="true" /> <h:outputLabel for="from" value="#{messages['agenda.evento.desde']}" /> <p:inputMask id="from" value="#{agendaBean.eventoSeleccionado.startDate}" mask="99/99/9999"> <f:convertDateTime pattern="dd/MM/yyyy" timeZone="GMT+1" locale="es_ES" /> </p:inputMask> <h:outputLabel for="to" value="#{messages['agenda.evento.hasta']}" /> <p:inputMask id="to" value="#{agendaBean.eventoSeleccionado.endDate}" mask="99/99/9999"> <f:convertDateTime pattern="dd/MM/yyyy" timeZone="GMT+1" locale="es_ES" /> </p:inputMask> <p:commandButton id="addButton" value="Save" actionListener="#{agendaBean.guaradarEvento}" update="agenda" oncomplete="dialogoEvento.hide();" /> <p:commandButton type="reset" value="Reset" oncomplete="dialogoEvento.hide();" /> </h:panelGrid> </p:dialog>
http://www.primefaces.org/showcase/ui/selectOneMenu.jsf
Este componente, está representado por un ComboBox que nos permite seleccionar un valor. En este ejemplo hemos ilustrado este componente mostrando los resultados ordenados por grupos.
El codigo html de ejemplo es:
<p:selectOneMenu id="selectOneMenu" value="#{manejadorComponentesInput.provinciaSeleccionada}"> <f:selectItem itemLabel="Elija provincia" itemValue="" /> <f:selectItems value="#{manejadorComponentesInput.provinciasAlfabeticas}" /> </p:selectOneMenu>
Para poder agrupar los resultados deberemos crear SelectItems e introducirlos en SelectItemGroup de la siguiente manera:
//Key es el label que queremos que se muestre en el grupo SelectItemGroup grupo = new SelectItemGroup(key); //setSelectItems requiere un array, para ello transformamos a array una lista de objetos de tipo SelectItems //Para ello hacemos uso de la clase Arrays grupo.setSelectItems(Arrays.copyOf(provs.get(key).toArray(), provs.get(key).toArray().length, SelectItem[].class));
http://www.primefaces.org/showcase/ui/selectOneRadio.jsf
Este componente crea un grupo de radiobuttons que nos permite seleccionar una opción de entre las expuestas. Al mismo tiempo nos permite diseñar el layout de los botones como queramos dándonos total libertad y permitiéndonos combinarlo con otro tipo de componentes.
Para poder crear un diseño personalizado tenemos que poner la opcion layout con valor custom. Para posteriormente codificar la visualización del mismo.
En el ejemplo que mostraremos a continuación hemos diseñado un radiobutton vertical con un componente adicional en cada opción.
<p:outputPanel id="panelRadio"> <p:selectOneRadio id="radiobut" value="#{manejadorComponentesInput.radioOption}" layout="custom"> <f:selectItem itemLabel="Opcion 1" itemValue="1" /> <f:selectItem itemLabel="Opcion 2" itemValue="2" /> <f:selectItem itemLabel="Opcion 3" itemValue="3" /> <p:ajax update="panelRadio" /> </p:selectOneRadio> <h:outputText value="#{manejadorComponentesInput.radioOption}" /> <h:panelGrid columns="3" cellspacing="10px;" id="panelCustomRadio"> <p:outputLabel for="opcion1" value="Valor" styleClass="nombreLabel" style="font-size:0.7em;" /> <p:radioButton id="opcion1" for="radiobut" itemIndex="0" /> <p:spinner style="margin-left:20px;" disabled="#{manejadorComponentesInput.radioOption!=1}" /> <p:outputLabel for="opcion2" value="Valoración" styleClass="nombreLabel" style="font-size:0.7em;" /> <p:radioButton id="opcion2" for="radiobut" itemIndex="1" /> <p:rating style="margin-left:20px;" disabled="#{manejadorComponentesInput.radioOption!=2}" /> <p:outputLabel for="opcion3" value="Teléfono" styleClass="nombreLabel" style="font-size:0.7em;" /> <p:radioButton id="opcion3" for="radiobut" itemIndex="2" /> <p:inputMask id="maskTlf" style="margin-left:20px;" value="#{manejadorComponentesInput.fecha}" mask="+99(999)-999999" required="true" validator="#{manejadorComponentesInput.validaFecha}" disabled="#{manejadorComponentesInput.radioOption!=3}"> </p:inputMask> </h:panelGrid> </p:outputPanel>
Importante: Actualmente hay un bug en chrome e IE que al refrescar con ajax el componente se queda deshabilitado, funciona correctamente en Firefox.
Cuando queremos incorporar un menú contextual en un árbol, si seguimos las instrucciones indicadas en el showcase de primefaces, nos encontramos ante el problema de que cada vez que queremos mostrar el menú se realiza un submit lo que causa pequeñas detenciones cada vez que queramos mostrarlo.
Estas detenciones resultan incómodas si queremos mostrar con relativa frecuencia el menú contextual.
Para solventar este problema se ha diseñado una solución que permite cargar el menú contextual inmediatamente retrasando el submit a la selección de una acción en dicho menú. En este caso es necesario diseñar un menú contextual diferente según los casos que tengamos.
El código fuente quedaría así:
<p:tree id="tTitulaciones" value="#{solicitudOfertaEnsenanzaBean.root}" var="titulacion" style="font-family:arial; font-size: x-small;" cache="true" dynamic="true" highlight="true" selectionMode="single" selection="#{solicitudOfertaEnsenanzaBean.selectedNode}" animate="true"> <p:treeNode type="padre"> <p:graphicImage value="/resources/img/#{titulacion.semaforo}.png" styleClass="ui-semaforo" /> <h:outputText value="#{titulacion.etiqueta}" /> </p:treeNode> <p:treeNode type="hijo"> <p:graphicImage value="/resources/img/#{titulacion.semaforo}.png" styleClass="ui-semaforo" /> <h:outputText value="#{titulacion.etiqueta}" /> </p:treeNode> </p:tree>
En esta definición del árbol indicamos un tipo para cada nodo diferente, cada tipo tendrá un menú contextual diferente asociado, de tal manera que, internamente por javascript, se dibujará el componente concreto sin necesidad de hacer el submit.
<s:div id="menuContextual" > <p:contextMenu for="tTitulaciones" widgetVar="menuContextual1" nodeType="padre" style="font-family:arial; font-size: x-small; width:180px" > <p:menuitem value="Menu 1" update="titulacionPanel" icon="ui-icon-info" oncomplete="PF('titulacionDialog').show()" /> </p:contextMenu> <p:contextMenu for="tTitulaciones" widgetVar="menuContextual2" nodeType="hijo" style="font-family:arial; font-size: x-small; width:180px" > <p:menuitem value="Menu 2" update="titulacionPanel" icon="ui-icon-info" oncomplete="PF('titulacionDialog').show()" /> <p:menuitem value="Menu 3" update="titulacionPanel" icon="ui-icon-info" oncomplete="PF('titulacionDialog').show()" /> </p:contextMenu> </s:div>
Por último en el bean de respaldo debemos asegurar que los nodos que se crean contienen los tipos tratados en el código xhtml
for(VwTitulacionesXCentro tituCentro : listaTitulaciones){ tituCentro.setTipoNodo("padre"); //Insertar en arbol TreeNode padre = new DefaultTreeNode(tituCentro.getTipoNodo(),tituCentro, root); //Si tiene hijos, insertar los hijos listaDepartamentosTitu = this.cargarDepartamentosXTitu(tituCentro.getId().getCodTitu() ); for(VwDepartamentosXTitu hijo: listaDepartamentosTitu){ hijo.setTipoNodo("hijo"); new DefaultTreeNode(hijo.getTipoNodo(),hijo, padre); } }
http://www.primefaces.org/showcase/ui/treeTableHome.jsf
Este componente nos permite combinar la funcionalidad de árbol con la claridad de agrupación de una tabla. La principal diferencia con un árbol es que todos los objetos deben devolver algún valor para cada una de las columnas, por lo que hay que tener en cuenta esto a la hora de mostrar los datos.
Este componente permite que se le añada un menú contextual para realizar acciones avanzadas. Este menú se mostrará al hacer clic derecho sobre el nodo correspondiente.
El código de ejemplo es el siguiente
<p:treeTable id="treetable" style="width:70%;" emptyMessage="No hay datos" selectionMode="single" value="#{manejadorComponentesInput.root}" var="prov"> <f:facet name="header"> Selector de provincias </f:facet> <p:column style="width:12%"> <f:facet name="header"> Provincia </f:facet> <h:outputText value="#{prov.proNombre}" /> </p:column> <p:column style="width:12%"> <f:facet name="header"> Longitud Nombre </f:facet> <h:outputText value="#{!prov.proCodigo.equals('no') ? prov.proNombre.length() : '--'}" /> </p:column> <p:column style="width:4%"> <f:facet name="header"> Acciones </f:facet> <p:commandLink styleClass="ui-icon ui-icon-search" /> </p:column> </p:treeTable>
CheckBox TreeTable
Esta es una variedad de el TreeTable normal que añade un checkbox a cada fila para realizar acciones determinadas sobre los elemento seleccionados. Su encabezado sería:
<p:treeTable value="#{ofertaAction.oferta5}" var="asi" selectionMode="checkbox" selection="#{ofertaAction.listadoOrigenOferta5}" id="panelAsiPrincipal"> ... ... </p:treeTable>
Las propiedades a destacar:
Bugs: Actualmente el árbol presenta un bug al borrar los elementos ya que entra en un bucle infinito al intentar hacer un “remove(Nodo)”.
Incidencia: Bucle infinito al borrar un nodo
La solución a este bug es utilizar la siguiente clase:
package automatricula.oferta.backbeans; import java.util.ArrayList; import org.primefaces.model.CheckboxTreeNode; import org.primefaces.model.TreeNode; public class FundewebTreeNode extends CheckboxTreeNode{ private static final long serialVersionUID = -5055108978844454329L; private TreeNode parent; public FundewebTreeNode(Object data, TreeNode parent) { super(data,parent); } @Override public void setParent(TreeNode parent) { this.parent = parent; } public TreeNode getParent() { return parent; } }
Como vemos esta clase extiende a CheckboxTreeNode y sobreescribe el método setParent que es el causante del error. Una vez creada esta clase cuando creemos nuestro árbol los nodos se deberán crear de este tipo.
TreeNode nodo = new FundewebTreeNode(...);
http://www.primefaces.org/showcase/ui/wizard.jsf
Este componente permite de manera sencilla crear un wizard para la inserción de datos en el sistema permitiéndonos navegación hacia delante y hacia atrás. Este comportamiento no incluye un botón “Finalizar” en la última pantalla por defecto, por lo que deberemos añadirlo nosotros mismos en el último formulario, o bien hacer un estilo de botones personalizado.
Las propiedades más relevantes del componente son las siguientes:
Un ejemplo de código
<p:wizard id="wizard" flowListener="#{wizardBean.cambioMenu}" widgetVar="wiz" backLabel="#{messages['pagination.before']}" nextLabel="#{messages['pagination.next']}"> <p:tab id="personal" title="#{messages['wizard.datos.pers']}"> <p:panel> <h:panelGrid columns="3" cellspacing="20px;"> <h:panelGroup> <p:outputLabel value="#{messages['madet.nombre.head']}" styleClass="nombreLabel" for="nombre" /> <p:inputText id="nombre" style="margin-left:20px;" required="true" /> </h:panelGroup> <h:panelGroup> <p:outputLabel value="#{messages['wizard.apellid']}" styleClass="nombreLabel" for="apellidos" /> <p:inputText id="apellidos" style="margin-left:20px;" required="true" /> </h:panelGroup> <h:panelGroup> <p:outputLabel value="#{messages['wizard.nacimiento']}" styleClass="nombreLabel" for="autocompletePojo" /> <p:autoComplete style="margin-left:20px;" value="#{manejadorComponentesInput.provinciaSeleccionada}" id="autocompletePojo" completeMethod="#{manejadorComponentesInput.autocompleteProvincia}" var="provincia" itemLabel="#{provincia.proNombre}" itemValue="#{provincia}" converter="conversorProvincias" forceSelection="true" required="true" /> </h:panelGroup> </h:panelGrid> </p:panel> </p:tab> <p:tab id="estadisticos" title="#{messages['wizard.datos.est']}"> <p:panel> <h3>Panel datos estadísticos</h3> </p:panel> </p:tab> <p:tab id="asignaturas" title="#{messages['wizard.datos.asig']}"> <p:panel> <h3>Selección de asignaturas</h3> </p:panel> </p:tab> <p:tab id="pago" title="#{messages['wizard.datos.pago']}"> <p:panel> <h3>Detalles del pago</h3> </p:panel> </p:tab> <p:tab id="fin" title="#{messages['wizard.datos.fin']}"> <p:panel> <h3>Panel resumen final</h3> </p:panel> </p:tab> </p:wizard>
En el caso que queramos personalizar los botones del wizard debemos ocultar la barra de navegacion showNavBar:false e incorporar después del wizard los botones correspondientes.
Para poder navegar hacia delante o hacia atrás debemos invocar la acción javascript correspondiente del wizard, para ello lo invocaremos usando el valor de la propiedad widgetVar=“wiz” de la siguiente manera:
<p:commandButton action="#{wizardBean.accion()}" id="anterior" oncomplete="wiz.back()" value="#{messages['pagination.before']}" style="float:left;"/> <p:commandButton action="#{wizardBean.accion()}" id="siguiente" oncomplete="wiz.next()" style="float:right;" value="Siguiente"/>
http://www.primefaces.org/showcase/ui/barChart.jsf
Este componente permite dibujar diferentes diagramas para mostrar datos. En este caso hemos escogido el diagrama de barras que tiene las siguientes propiedades de interés:
El código fuente para el diagrama es el siguiente:
<p:barChart id="basico" value="#{manejadorComponentesInput.chartBarras}" legendPosition="nw" title="#{messages['diagrama.barras.titulo']}" min="0" max="210" style="height:400px" legendCols="1" shadow="true" animate="true" showDatatip="true" datatipFormat="#{manejadorComponentesInput.formatoBarra}" />
http://www.primefaces.org/showcase/ui/exporter.jsf
Este componente nos permite exportar en diferentes formatos(PDF,XML,XSL,CSV) el contenido de una tabla. Permitiéndonos exportar toda la tabla o sólo la página que estamos viendo. Importante: Para la exportación de PDF hay que asegurarse de que tenemos la librería de iText configurada en nuestro proyecto.
Las propiedades más importantes son:
En la tabla
En el componente
El código de ejemplo es el siguiente:
<h:commandLink style="float:right;"> <p:graphicImage value="/resources/img/xml.png" /> <p:dataExporter type="xml" target="listaAnuncios" fileName="listado" pageOnly="true" /> </h:commandLink> <p:dataTable id="listaAnuncios" var="anuncio" value="#{manejadorAnuncios.buscadorAnuncios}" paginator="true" rows="10" paginatorPosition="bottom" paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}" rowsPerPageTemplate="5,10,15,30" selection="#{manejadorAnuncios.anuncioSeleccionado}" lazy="true" emptyMessage="#{messages['datatable.sinresultados']}"> <p:column sortBy="#{anuncio.id}"> <f:facet name="header"> <h:outputText value="#{messages['madet.num.head']}" /> </f:facet> <h:outputText value="#{anuncio.id}" /> </p:column> </p:dataTable>
http://www.primefaces.org/showcase/ui/datatablePagination.jsf
Tabla que muestra los elementos almacenados en el bean de respaldo en forma de listado. Primefaces nos proporciona diversos tipos de tablas, siendo la más recomendable la tabla paginada con carga difertida (LazyLoad DataTable) que es la que tratamos en este ejemplo.
Dicha tabla nos provee de filtrado, ordenamiento y paginación manteniendo en memoria sólo la información que se está mostrando. Para ello necesitamos crear una estructura de clases concreta para que el componente realice las cargas conforme vayamos paginando.
Las principales propiedades de este componente son las siguientes:
El código html de ejemplo de esta tabla es el siguiente:
<p:dataTable id="listaAnuncios" var="anuncio" value="#{manejadorAnuncios.buscadorAnuncios}" paginator="true" rows="10" paginatorPosition="bottom" paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}" rowsPerPageTemplate="5,10,15,30" selection="#{manejadorAnuncios.anuncioSeleccionado}" lazy="true" emptyMessage="#{messages['datatable.sinresultados']}">
Hay que destacar que manejadorAnuncios.buscadorAnuncios, devuelve una clase que extiende la clase abstracta LazyDataModel. Esta clase nos provee del mecanismo de carga bajo demanda que necesitamos para nuestra tabla.
El código de esta clase para el ejemplo es el siguiente:
public class LazyAnuncioDataModel extends LazyDataModel<Anuncio> { private static final long serialVersionUID = -7128353552033320971L; private ServicioAnuncios servicioAnuncios; private String namedQuery; private String countQuery; private HashMap<String, Object> parametros; private List<Anuncio> anuncios; public LazyAnuncioDataModel(ServicioAnuncios servicioAnuncios) { this.servicioAnuncios = servicioAnuncios; anuncios = new ArrayList<Anuncio>(); } @Override public Object getRowKey(Anuncio anuncio) { return anuncio.getId(); } @Override public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) { // En este ejemplo básico no utilizamos ni el sort ni los filtros if (parametros == null) { parametros = new HashMap<String, Object>(); } //Obtenemos los anuncios que ocupen la posicion first hasta pageSize anuncios = servicioAnuncios.ejecutaNamedQuery(namedQuery, parametros, first, pageSize); //Indicamos el número total de registros de la consulta (para poder establecer el número de páginas) setRowCount(servicioAnuncios.obtenTotalRegistros( countQuery, parametros)); if (anuncios != null) { return anuncios; } else { return new ArrayList<Anuncio>(); } } @Override public Anuncio getRowData(String rowKey) { for (Anuncio an : anuncios) { if (Long.toString(an.getId()).equals(rowKey)) return an; } return null; } }
Este componente muestra una tabla con ScrollVertical infinito con carga dinámica. El funcionamiento es similar a la carga de listados en Twitter o Facebook. Se precargan N valores y conforme se hace Scroll se cargan el resto.
— Falta link —
http://www.primefaces.org/showcase/ui/feedReader.jsf
Este componente nos permite leer un rss dado y formatear por pantalla el resultado final que presentaremos al usuario.
<p:feedReader id="rss" value="#{manejadorPrimeRss.rss}" var="feed"> <br/> <h:outputText value="#{feed.title}" style="font-weight: bold;" /> <p:separator /> <h:outputText value="#{feed.description.value}" escape="false"/> <p:spacer width="25"/> </p:feedReader>
http://www.primefaces.org/showcase/ui/gmapHome.jsf
Este componente pinta un mapa de google en nuestra aplicación y nos permite interactuar con él. Así pues podemos dar de alta marcadores o consultar su información.
Para que el mapa se muestre hay que añadir el siguiente código a la cabecera de nuestra página web:
<script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script>
Importante: El componente aún no funciona correctamente (pendiente de estabilizar). Podemos utilizarlo para visualizar marcadores puestos y consultar la información que hayamos dispuesto para ellos, pero no nos permite insertar uno e inmediatamente consultar la información introducida. No se puede hacer un “update” del componente ya que desaparece, y el bean de respaldo sobre el que se basa ha de tener ámbito de Sesión.
El código a continuación mostrado combina la visualización de la información con la introducción de la misma, pero actualmente no funcionan ambas cosas a la vez.
<p:gmap id="map" center="38.022860,-1.174731" zoom="17" type="HYBRID" model="#{manejadorComponentesInput.modeloMapa}" widgetVar="map" style="width:600px;height:400px" onPointClick="preparaMarcador(event);" streetView="true"> <p:ajax event="pointSelect" listener="#{manejadorComponentesInput.onMapPointSelect}" oncomplete="crearMarcadorDialog.show()" /> <p:ajax event="overlaySelect" listener="#{manejadorComponentesInput.onMarkerSelect}"/> <!-- Ventana de informacion --> <p:gmapInfoWindow> <p:outputPanel style="text-align:center;display:block;margin:auto;"> <h:outputText value="-#{manejadorComponentesInput.marcadorSeleccionado.title}-" /> </p:outputPanel> </p:gmapInfoWindow> </p:gmap>
http://www.primefaces.org/showcase/ui/commandLink.jsf
Botón para realizar una acción contra el servidor. Como novedad, la acción ajax viene configurada como acción por defecto en vez de un submit normal. Este componente permite reRenderizado y procesamiento parcial de los datos. Las propiedades principales son las siguietnes:
Un ejemplo de código
<p:commandButton value="#{messages['madet.buscar']}" icon="ui-icon-search" id="btnBuscar" ajax="false" update=":formularioResultados" process="@this,panelFiltro" action="#{manejadorAnuncios.buscar()}" />
http://www.primefaces.org/showcase/ui/dialogHome.jsf
Componente para crear un modalPanel que aparezca como un popUp para que podamos realizar acciones adicionales, consultar datos, utilizar como ayuda, etc…
Dentro de sus propiedades principales podemos destacar:
<p:dialog id="panelModal" header="Crear comentario" width="500" position="top" height="350" widgetVar="panelComentario" style="position:fixed;margin-top:10%;" modal="true" closable="true" appendToBody="true" resizable="false"> <h:form id="modalPanelForm"> <h:outputText value="#{messages['det.coment.text']}" styleClass="nombreLabel" /> <p:editor id="editComentario" width="400" value="#{manejadorAnuncios.comentarioSeleccionado.texto}" /> <div style="position:absolute;bottom:10;width:95%;"> <p:commandButton id="btnCancelComent" value="#{messages['value.cancel']}" style="float:right;" icon="ui-icon-close" ajax="true" action="true" onclick="panelComentario.hide();"/> <p:commandButton value="#{messages['value.save']}" id="btnGuardarComent" icon="ui-icon-disk" ajax="true" action="#{manejadorAnuncios.guardarComentario()}" style="float:right;margin-right:15px;"/> </div> </h:form> </p:dialog> ... ... ... <!-- Llamada al panel --> <p:commandButton id="btnNuevoAnun" icon="ui-icon-document" style="float:right;margin-bottom:10px;" value="#{messages['det.coment.nuevo']}" onclick="panelComentario.show();" />
http://www.primefaces.org/showcase/ui/menubar.jsf
Este componente nos proporciona una barra de menú horizontal a la que podremos ir añadiéndole opciones. Se comporta de manera idéntica a una barra de menú de cualquier aplicación de escritorio. A la hora de construir el menú podemos diferenciar los siguientes elementos:
Un ejemplo de código es el siguiente:
<p:menubar id="menuBar"> <p:menuitem value="#{messages['value.link.home']}" icon="ui-icon-home" url="/paginas/home.xhtml" /> <p:submenu label="#{messages['value.link.comp']}" icon="ui-icon-document"> <p:menuitem value="#{messages['value.link.madet']}" url="/paginas/maestroAnuncios.xhtml" icon="ui-icon-newwin"/> </p:submenu> <f:facet name="options"> <p:commandButton value="Salir" icon="ui-icon-extlink" action="#{identity.logout()}" /> </f:facet> </p:menubar>
http://www.primefaces.org/showcase/ui/messages.jsf
Componente para mostrar los mensajes faces que produzca el sistema. Creará una barra superior que agrupará los mensajes del mismo tipo en ella. Fundeweb por defecto lo incorpora en sus templates, por lo tanto no es necesario introducirlo en las aplicaciones desarrolladas con este framework.
<p:messages id="messages" showDetail="false" closable="true"/>
http://www.primefaces.org/showcase/ui/blockUI.jsf
Permite bloquear componentes jsf cuando se está ejecutando ajax.
http://www.primefaces.org/showcase/ui/collector.jsf
Permite gestionar colecciones en cliente (crear, eliminar). Minimiza las llamadas al servidor.
http://www.primefaces.org/showcase/ui/hotkey.jsf
Liga las teclas al cliente para realizar acciones.
http://www.primefaces.org/showcase/ui/sticky.jsf
Este componente permite que un elemento de nuestra página siempre quede visible aunque esta tenga scroll vertical. Alinea el componente en el top de la pantalla y lo mantiene visible en todo momento.
Cuando introducimos el componente editor en un panel, a la hora de pintar el panel, lo hacemos normalmente por javascript, por lo tanto el editor no se encuentra preparado para la edición cuando se pinta, para ello debemos actualizar el formulario que contiene dicho editor.
<p:commandButton id="btnNuevoCom" icon="ui-icon-document" ajax="true" action="#{manejadorAnuncios.creaNuevoComentario()}" value="#{messages['det.coment.nuevo']}" oncomplete="panelComentario.show();" update=":modalPanelForm"/>
En este código se muestra cómo se pinta el panel desde un botón. En el “oncomplete” nos encargamos de pintar el panel mediante javascript, la modificación importante es update=“:modalPanelForm” ahí es donde indicamos que actualice el formulario, que en este caso contiene el editor.
A la hora de hacer un update y que nos repinte un componente, debemos poner el clientID, bien en ruta relativa o absoluta. El problema surge porque ese ID no es siempre la cadena de ID de los contenedores ya que en JSF no todos los elementos que pueden agrupar contenido son considerados contenedores, lo que nos plantea problemas a la hora de saber exactamente cuál es la ruta de ID's hasta un determinado componente.
La solución a este problema es crear un <h:outputText> al miso nivel del componente que queremos conocer su ID, en el campo value, ponemos lo siguiente #{component.clientId}.
Tras hacer esto lanzamos otra vez la página y se nos imprimirá en pantalla, donde pusimos el <h:outputText>, la ruta de ID's hasta ese campo, incluido su ID. Una vez impreso, copiamos esa ruta y sustituimos el ID por el de nuestro componente.