RichFaces, trabajando con tablas (3): ordenación y filtrado manuales

Enviado por Jesús Salinas R... el Lun, 03/14/2011 - 20:13.

Introducción

El uso de los atributos sortBy y filterBy del componente rich:column NO será válido cuando se trabaja con modelos de datos complejos como el que se presentó en el artículo "RichFaces, trabajando con tablas (2)". Se deben implementar mecanismos de ordenación y filtrado manuales que sean capaces de manejar este modelo paginado. 

Se van a definir commandLinks dentro de las columnas de la tabla que van a lanzar peticiones Ajax para modificar el orden en el que se muestran los datos dentro del dataTable.

Se van a crear inputText para definir mecanismos de filtrado.

Ordenación manual

Modificaciones en la vista

Para aplicar ordenación sobre una estructura de datos compleja se debe modificar la renderización. Se incorpora una nueva acción dentro de la faceta de cabecera que pasa como parámetro, en la petición que genera, el campo a partir del cuál se va a ordenar.

Por ejemplo, si se hace click sobre la columna Código de factura se enviará un parámetro llamado sortField cuyo valor será codfactura y cuando se genere la respuesta se re-renderizará la tabla paginada:

<h:column>
 <f:facet name="header">
    <a4j:commandLink value="Código de factura" reRender="tabla">
       <a4j:actionparam name="sortField" value="codfactura" />
    </a4j:commandLink>
 </f:facet>
 <h:outputText value="#{f.codfactura}"></h:outputText>
</h:column>

¿En este caso se deben utilizar atributos para optimizar el envío de información? ¿ajaxSingle = “true”? No, la petición desencadenada por esta acción debe enviar la información de la tabla para poder procesarla mediante el ciclo de vida estándar.

¿Algún tipo de renderización adicional? Queremos que, una vez que el orden de los datos sea modificado, sólo sea re-renderizada la tabla. Los demás contenidos de la página deben quedar intactos.

Por esta razón, se utiliza en atributo reRender asociado a la tabla.

<rich:dataTable id="tablaFacturas" value="#{paginacion2.facturas}"
                var="f" rows="5" reRender="scroll01" width="100%">
<rich:column id="concepto">
<f:facet name="header">
<h:outputText value="Concepto"></h:outputText>
</f:facet>
<a4j:commandLink id="accion" ajaxSingle="true" limitToList="true">
<h:outputText value="#{f.concepto}" />
</a4j:commandLink>
</rich:column>
<rich:column>
<f:facet name="header">
<a4j:commandLink value="Código de factura" reRender="tablaFacturas">
<a4j:actionparam name="sortField" value="codfactura" />
</a4j:commandLink>

</f:facet>
<h:outputText value="#{f.codfactura}"></h:outputText> </rich:column>

El método update()

El modelo de datos propuesto en el artículo "RichFaces, trabajando con tablas (2)" incorpora un método llamado update() como responsable de todos los procesos de actualización del modelo. Este método se ejecuta, dentro del ciclo de vida JSF en la fase de actualización del modelo, como resultado de una acción dentro de la tabla que, evidentemente, tiene que enviar la tabla como parte de la información a procesar en el servidor. El caso que estamos analizando cumple todas esas condiciones. Por esta razón, este método nos va a permitir implementar el concepto de ordenación.

...
public void update() {
     // Codigo para cambiar el criterio de ordenación.
}
...

Se muestra a continuación código de ejemplo:

@Override
public void update() {    // Paso 1: Se comprueba si se aplica criterio de ordenación.
  if(getCriterioOrdenacion()!=null){
        // Paso 2: Se recupera al criterio de ordenación a aplicar.
        final String nuevoCriterio = getCriterioOrdenacion().toString(); 
        // Paso 3: Se comprueba si el criterio de ordenación es igual al que está activo.
        if(nuevoCriterio.equals(dataProvider.getOrdenacion())){
          // Paso 4: Si el criterio de ordenación es el mismo, debemos cambiar
          //         el orden.
          dataProvider.setDescendente(!dataProvider.isDescendente());
        }
        dataProvider.setOrdenacion(nuevoCriterio);
   }
   // El atributo detached indica si el modelo de datos está serializado o si hay
   // que volver a la base de datos a recuperar la información de nuevo.
   // En el caso de un cambio de ordenación, debemos lanzar una nueva consulta.
   detached = false;
}

Como se ha podido ver en el código, se crea y utiliza un método auxiliar llamado getCriterioOrdenacion para manejar el criterio de ordenación:

protected Object getCriterioOrdenacion(){
      // Paso 1: Se recupera el contexto JSF
     final FacesContext contexto = FacesContext.getCurrentInstance();
     // Paso 2: Se obtiene el parametro pasado en la petición.
     final Object o =
           contexto.getExternalContext().getRequestParameterMap().get("sortField");
     return o;
}

El método getItemsByRange del proveedor

Lógicamente, este método debe ser modificado para manejar el concepto de ordenación. Por ejemplo

servicioContabilidad.findAllPaginandoOrdenando(inicio, tam, asc, propiedad);

Análisis del ciclo de vida

La primera vez que se quiere visualizar la página, el ciclo de vida (como ya hemos comentado anteriormente es más corto):

  • Fase de restauración de la vista.
  • Fase de renderización
    • En esta fase se ejecutan los métodos del modelo de datos anteriormente descritos. En el caso del método walk(), como la variable detached está a falso, obligatoriamente accede a base de datos y recupera SÓLO los objetos que va a mostrar la tabla. El número de objetos cargados en memoria es mucho menor que en el primero caso.
    • Posteriormente, se ejecuta el método getSerializableModel() que devuelve el modelo serializado poniendo la variable detached a verdadero (esto provoca que cuando se hagan peticiones sobre la página -Postbacks- no se recupere el modelo de la base de datos, ya que se encuentra serializado).

Una vez que la página se renderiza, se muestra:

Al hacer click sobre el enlace Código de factura se genera una petición al servidor. En ese caso se desencadena un ciclo de vida completo:

  • La petición es de tipo POSTBACK, es decir, el modelo está serializado y la variable detached está a true, por lo tanto, aunque se ejecute el método walk() del modelo NO se lanzan consultas a la base de datos.
  • Cuando se llega a la fase de actualización se ejecuta el método update(). Éste cambia el criterio de ordenación y pone la variable detached a falso.
  • En la fase de renderización, como detached está a falso, cuando se ejecuta el método walk() se accede a la base de datos aplicando el criterio de ordenación seleccionado. Como en la vista el atributo reRender está asociado a la tabla, ésta vuelve a renderizarse con los nuevos valores.

Filtrado manual

Conceptualmente, este proceso es muy parecido al de ordenación. Se debe modificar la vista para incorporar un campo que actúe como filtro y, posteriormente, se debe modificar el modelo de datos que proporciona registros a la tabla para que cuando se active el filtro actúe en consecuencia.

Modificaciones en la vista

Se incorpora un campo de texto que genera peticiones AJAX para activar el proceso de filtrado:

...
<rich:column id="concepto">
  <f:facet name="header">
    <h:outputLabel value="Concepto" for="filtroConcepto"></h:outputLabel>
    <h:inputText id="filtroConcepto"                  
                 value="#{paginacion2.facturas.dataProvider.filtroConcepto}"                  
                 style="width:90px" >         
       <a4j:support event="onblur" reRender="tablaFacturas,scroll01"              
                    ajaxSingle="true" limitToList="true">         
       </a4j:support>     
    </h:inputText> 
  </f:facet>
  <h:outputText value="#{f.concepto}" />
</rich:column>
...

Modificaciones en el método getItemsByRange()

Se debe modificar este método para que sea capaz de manejar filtros:

...
 rango = servicioContabilidad.
         findAllPaginandoOrdenandoFiltrado(
           firstRow, 
           endRow, 
           !descendente, 
           ordenacion, 
           filtroConcepto);
...

El resultado de estas modificaciones generan la siguiente vista:

Si se escribe en el filtro se genera un filtrado:

Código de ejemplo

Aquí tenéis un ejemplo que ilustra la funcionalidad descrita en el post. Este proyecto web ha sido desarrollado utilizando:

  • Eclipse Helios y Maven.
  • Servidor de aplicaciones JBoss 4.2 y base de datos MySQL.

Las tecnologías utilizadas son:

  • JSF+RichFaces Frameworks en capa de presentación.
  • Spring Framework en capa de negocio.
  • Hibernate Framework en capa de datos.

Descárgalo desde aquí.

AdjuntoTamaño
Proyecto web RichFaces con ordenación y filtrado de tablas manual32.45 KB

10 comments

Gracias por tu ayuda.

Enviado por Anónimo el Mié, 09/12/2012 - 23:08.

 Gracias por tu aprote me ayudo bastante pero tengo una dudo sobre los filtros. 

El filtro que logro es el que me filtra buscando desde el inicio del campo pero en el ejemplo de livedemo.exadel.com/richfaces-demo/richfaces/dataTable.jsf

aparec[url=http://livedemo.exadel.com/richfaces-demo/richfaces/dataTable.jsf?tab=modifiableDataModel&cid=1587872]e un filtro mejor, tendras un ejemplo sencillo sobre como realizarlo.[/url]

ReRender datascroller

Enviado por Anónimo el Jue, 05/12/2011 - 17:07.

Buenas!! Muy bueno el artículo, me ha ayudado mucho. El único problema es que no me renderiza el DataScroller despues de filtrar. Por lo que si al filtrar solo obtengo dos resultados, al no renderizar el Datascroller, me siguen apareciendo 10 página.¿Sabeis como puedo solucionar este problema?
Gracias y un saludo!

¿Bug en rich:dataScroller?

Enviado por Anónimo el Lun, 05/09/2011 - 14:54.

 Hola, buenas tardes;Hace aproximadamente seis meses que tuve que afrontar este desarrollo para un framework corporativo, pero en general lo hice siguiendo el modelo expuesto en eclectic programmer.Sin embargo hay un último fallo que no consigo arreglar y por tus capturas deduzco que tú tampoco.Si tomamos como ejemplo las dos últimas capturas de este artículo, el rich:dataScroller muestra siempre 5 páginas disponibles. En el primer caso es correcto, pero en el último debería estar vacío al no haber más que una página (como comportamiento por defecto del componente).¿Conoces alguna solución Jesús?Muchas gracias.

Bug en rich:dataScroller, Solución

Enviado por Anónimo el Vie, 05/13/2011 - 12:10.

Buenos días, he estado mirando el tema del scroll. Despues de filtrar no se aplica el rerender al scroll. Lo que he hecho ha sido que despues de recuperar la lista de Objetos a listar, en mi ejemplo: [b]
   List<Object[]> documentosList = documentosService.getListaDocumentos(
usuario.getUser(), firstRow, endRow, desc, ordenacion,filtroNombre, filtroDescripcion);[/b]

hago lo siguiente:

   [b]if(documentosList.size()<10) {this.size = 0;}[/b]
Quiere decir, que si el tamaño de la lista es menor al valor del atributo del DataScroller "maxPages" (en mi caso 10), entonces le asigno el valor 0 al atributo "size" de la clase provider (en mi casp "DocumentosDataProvider" ).

Un saludo!!

Bug en rich:dataScroller, Solución (Corrección)

Enviado por Anónimo el Vie, 05/13/2011 - 13:37.

Un apunte más, hay que poner algo más si no el scroll hace cosas raras:

Donde yo pongo: [b] if (documentosList.size() < 10) {this.size = 0;}[/b]

Hay que completarlo con lo siguiente (sustituir lo de arriba por lo siguiente)
[b]if (documentosList.size() < 10) {
this.size = 0;
}
else if(this.size!=null && this.size==0)
{
this.size = null;
this.size = this.getRowCount();
}[/b]Esto lo hago para que cuando no haga falta el Scroll, pues que lo vuelva a poner informando el atributo "size"
Un saludo!!

Y en RichFaces 4 sigue el mismo modelo??

Enviado por Anónimo el Dom, 05/08/2011 - 03:08.

Hola Jesus me llamo Miriam desde Bolivia y estoy aprendiendo jsf con richfaces en primera oportunidad estaba aprendiendo richfaces 333 pero ahora que veo que ya salio richfaces 4 mi pregunta es si sigue siendo valida esta paginacion o ya existe otro componente en richfaces 4 para la paginacion desde la base de datos 

Un ejemplo con Super clase

Enviado por Anónimo el Mar, 04/26/2011 - 23:07.

Hola Jesus me encanto tu tutorial para la paginacion te cuento que encontre otro con una Superclase queria saber tu opinion te dejo el link para que lo revises pero seguramente ya lo encontraste por ahi.
http://eclecticprogrammer.com/2008/07/30/a-generic-superclass-for-sortin...

Bueno espero tu opinion gracias chauuuu

RE: Un ejemplo con Super clase

Enviado por Jesús Salinas R... el Mié, 04/27/2011 - 23:23.

Hola,
Efectivamente, ya había visto el artículo. Le da una vuelta de tuerca al modelo que hemos planteado en nuestro artículo. Ambas estrategias son válidas. Podemos utilizar cualquiera de las dos.
Un saludo y muchas gracias por tu aportacion, se agradece, 

problemas con el modalPanel

Enviado por Anónimo el Mié, 04/20/2011 - 15:12.

Que buen ejemplo muy completo para lo que se requiere pero tengo una duda estoy intentando trabajar con modalPanels para confirmar la edicion de un registro pero no me esta funcionando muy bien talvez tuvieras algun ejemplo para trabajar con modalPanels?

RE: problemas con el modalPanel

Enviado por Jesús Salinas R... el Mié, 04/27/2011 - 23:33.

Hola,
Pues efectivamente, el uso combinado de tablas paginadas y modalPanel hay que manejarlo con cuidado.
El próximo artículo sobre paginación con RichFaces describe esta problemática. La semana que viene lo tendrás en la web. De cualquier forma, si me cuentas de manera más detallada qué problema te estás encontrando, intentaré ayudarte en la medida de lo posible.
Un saludo.

Drupal theme by Kiwi Themes.