martes, 29 de junio de 2010

Ajax en JSF 2.0 - Ejemplo 2: Tabla actualizada según se escriba

Siguiendo con los ejemplos después de mucho tiempo, ahora mostraré cómo actualizar una lista dependiendo del texto que se escribe en un input-text, pero usando Ajax. Es decir, a medida que se escribe, se actualizará el contenido del texto. Todo esto usando JSF 2.0 con su tag <ajax />


El EJB

Para comenzar, debemos tener un lista de elementos que se actualizarán de acuerdo a un parámetro. Yo tengo un EJB que hace una consulta por JPA-API a mi base de datos "samples" (Esta base de datos viene como parte de las bases de datos de ejemplo de Java DB / Apache Derby y que son accesibles desde NetBeans). La entidad que estoy manejando es el Manufacturer.


public List<Manufacturer> findByName(String name) {        
  String $name = "%" + name.replaceAll(" ", "%") + "%";        
  CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();          
  CriteriaQuery<Manufacturer> criteriaQuery = criteriaBuilder.createQuery(Manufacturer.class);        
  Root<Manufacturer> manufacturer = criteriaQuery.from(Manufacturer.class);        
  criteriaQuery.select(manufacturer);        
  criteriaQuery.where(criteriaBuilder.like(manufacturer.get("name").as(String.class), $name));        
  List<Manufacturer> list = em.createQuery(criteriaQuery).getResultList();        return list;    
}

El ManagedBean

Ahora, el ManagedBean que se comunicará con la interfaz de usuario y le dirá qué mostrar. Este tiene un atributo llamado "nombre" que estará asociado al input-text del formulario que el usuario verá. Lo que escriba se guardará ahí, y será tomado para la búsqueda en la base de datos.


@ManagedBean(name = "formBean")
@SessionScopedpublic class ManufacturerManagedBean {
    static final Logger LOGGER = Logger.getLogger(ManufacturerManagedBean.class.getName());
    @EJB
    private ManufacturerFacade manufacturerFacade; //el EJB
    private String nombre = ""; //el atributo que estará asociado al input-text
    private List<Manufacturer> manufacturerList; //la lista a mostrar
    /** Creates a new instance of ManufacturerManagedBean */
    public ManufacturerManagedBean() {
    }
    public String getNombre() {
        return nombre;
    }
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
    public List<Manufacturer> getListByName() {
        if (manufacturerList == null) { //si es la primera vez que se accederá a la lista...
            manufacturerList = manufacturerFacade.findByName(nombre); //... actualizar el contenido
        }
        return manufacturerList; //devuelve la lista con los elementos encontrados
    }
    public void nombreChangeListener(AjaxBehaviorEvent  event) {
        //cada vez que haya un cambio en el texto, vuelve a generar la lista
        manufacturerList = manufacturerFacade.findByName(nombre);
    }
}

El .xhtml

Y, en la tercera capa, vemos el .xhtml que mostrará el contenido actualizado y el formulario.

El contenido será mostrado en un <h:dataTable /> como cualquier resultado. Tendrá como ID=manufacturerTable. Este ID es importante porque es por donde el Ajax le dirá qué elemento de la página debe actualizar.

<h:dataTable value="#{formBean.listByName}" border="1" var="item" id="manufacturerTable">
                <h:column>
                    <f:facet name="header">
                        ID
                    </f:facet>
                    <h:outputText value="#{item.manufacturerId}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        Nombre
                    </f:facet>
                    <h:outputText value="#{item.name}" />
                </h:column>
                <h:column>
                    <f:facet name="header">
                        e-mail
                    </f:facet>
                    <h:outputText value="#{item.email}" />
                </h:column>
            </h:dataTable>

Ahora, la parte más esperada: el input-text con el Ajax.

Realmente consiste en un tag h:inputText que tiene dentro un tag f:ajax. El que hace realmente el trabajo es este último tag.

            <h:inputText id="nombreFiltro" autocomplete="off" value="#{formBean.nombre}"  >
                <f:ajax render="manufacturerTable" event="keyup" listener="#{formBean.nombreChangeListener}"/>
            </h:inputText>

  • El atributo render dice qué IDs del HTML se van a actualizar. Aquí dice que es el ID del dataTable.
  • El atributo event dice qué evento del tag inputText (porque está manejando los eventos del tag que lo envuelve) va ejecutar el ajax. En este caso será el evento keyup del input-text.
  • El atributo listener indica cuál es el método que se ejecutará cuando suceda el evento. En este caso es el método nombreChangeListener del ManagedBean que hemos creado hace un momento.

Y listo, lo ejecutamos y ya.

El proyecto


Este proyecto, como todos los demás, debería ejecutarse si problemas en un NetBeans IDE 6.8/6.9, usando GlassFish v3. Aquí está para descargarlo.


10 comentarios:

  1. Muy buen articulo Diego.

    Quiero hacer un pequeño aporte a indicando que es posible actualizar una lista de campos, por medio del argumento render algo como esto:

    f:ajax render="manufacturerTable campo1 campo2 ..." ...

    Util por ejemplo cuando tenemos un formulario que deseamos refrescar segun el Id digitado por el usuario

    ResponderEliminar
  2. HOLA, OYE LAVERDAD ES QUE ME HAN GUSTADO TUS ARTICULOS Y ME PARECEN MUY BUENOS, YO TRABAJE CON FACES 1.2 Y CON EL FACES CONFIG, PERO AHORA QUE ME HE MUDADO A FACES 2.0 NO PUEDO HACER QUE FUNCIONE LAS ANOTACIONES, ES DECIR QUE HAGO EL BEAN Y TRATO DE INTERACTUAR CON EL Y NO FUNCIONA ME DICE QUE LA ETIQUETA DEL MB DECLARADA EN LA ANOTACION NO EXISTE QUE NO ENCUENTRA EL BEAN, ME PODRIAS AYUDAR????

    ResponderEliminar
  3. Hola
    te has asegurado que está ejecutándose en un servidor JavaEE 6 ? Porque esta anotación es nueva en esta versión.

    ResponderEliminar
  4. Hola, te comento que no se puede acceder al archivo que publicaste.

    ResponderEliminar
  5. Listo, gracias anónimo :)
    resulta que el sitio java.net está migrando de plataforma. Ya actualicé el enlace. Seguiré revisando los demás post.

    gracias nuevamente

    ResponderEliminar
  6. Muy bueno Diego, una pregunta, ¿como podría hacer esto mismo solo que sin utilizar EJB y solo utilizando clases Java y ManagedBeans con una BD en MySQL? estoy empezando a ver JSF 2.0 y me gustaría algo como esto... Gracias y buen ejemplo

    ResponderEliminar
  7. Hola buen ejemplo, me gustaría que me explicaras que diferencias tiene un SessionScopedpublic de un SessionScoped

    Saludos

    ResponderEliminar
  8. Hola excelente articulo me funciono correctisimo. Tengo una situacion, en mi bd tengo los registros mezclados con letras minusculas y/o mayusculas, pero al escribir en el inputText si lo escribo todo minuscula por ejemplo y en la bd se encuentra con letra inicial mayuscula obviamente no coincide y no me lo devuelvo como puedo hacer para que digamos el valor que viene de la bd me lo pase a minuscula para que todo lo que escriba me lo pase tambien a minuscula y de esa manera supongo hara una comparacion de caracteres todo en minusculas, espero me haya dado a comprender.

    Puedes echarme una mano y como poder resolver esta situacion

    De antemano muchas gracias

    ResponderEliminar
    Respuestas
    1. Hola Manfredo

      estas usando JPA como en este ejemplo? si es así, intenta con cambiar la línea 7 del primer código de este ejemplo (o en el mismo código fuente, en la línea 33 de la clase ManufacturedFacade.java) con lo siguiente:

      criteriaQuery.where(criteriaBuilder.like( criteriaBuilder.upper( manufacturer.get("name").as(String.class)), $name.toUpperCase()));

      Si te das cuenta, se trata de hacerlo uniforme: todo en mayúsculas tanto el campo de la tabla (criteriaBuilder.upper()) como el argumento ($name.toUpperCase()).

      Eliminar

Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups


Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/