En la versión 2.0 de JavaServer Faces tiene soporte implícito para Ajax ya que cuenta con una librería para tal fin, por lo que no será necesario escribir ni una sola línea de código javaScript para poder usar Ajax.
Para usar Ajax en nuestros facelets solo se necesita incluir el tag f:ajax y definir los atributos que necesitemos, esta es su lista de atributos:
- disabled: Si se le da el valor de true no se ejecutara la acción Ajax (false por defecto).
- event: Con este atributo se puede indicar el evento que desencadenará la petición Ajax. Por defecto es action para los botones y enlaces y valueChange para el resto de compontes pero además de estos eventos especiales y específicos de JSF se pueden usar los eventos propios de HTML como blur, change, keydown, focus, mouseover, etc (los eventos onXXX quitando el on de delante).
- execute: En este atributo hay que indicar el id del componente (o componentes) que se quiere enviar al servidor para procesarlo. En caso de ser varios componentes los ids tienen que estar separados por un espacio en blanco (execute=»unId otroId otroIdMas»).
- immediate: Sirve para indicar si queremos que la acción se realice en la fase de ciclo predefinida, la fase 5 (Invoke Aplication) o en la fase 2 (Apply request values) si lo establecemos a true.
- listener: Nombre del método que se ejecutará en respuesta a la petición Ajax. Este método tiene que tener un atributo de la clase AjaxBehaviorEvent, (por ejemplo: public void hacerAlgo(AjaxBehaviorEvent e) {// Lo que haga}).
- onevent: El nombre de la fución javaScript que se encarga de manejar el evento.
- onerror: El nombre de la fución javaScript que se encarga de manejar los errores.
- render:Aquí hay que indicar el nombre del componente o componentes que se va actualizar como consecuencia de la petición. Además de los ids de los elementos se puede usar @all, @form, @none y @this, para actualizar todos los componentes, todos los componentes del formulario desde el que se hizo la petición, ningún componente o el componente desde el componente desde el que se lanzo la petición (este es el valor por defecto).
Una vez vistos los atributos y para que sirven vamos a ver un ejemplo de como usar Ajax con JSF.
En este ejemplo vamos a hacer una especie de formulario de login y vamos a hacer unas sencillas validaciones de los campos con Ajax y al pulsar en el botón mostrar un mensaje con los datos introducidos. El ejemplo en cuestión no tiene más sentido que probar el uso de f:ajax.
El facelet del ejemplo es el siguiente:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="./../resources/css/estilo.css" rel="stylesheet" type="text/css" />
<link href="./../resources/css/estilo-formularios.css" rel="stylesheet" type="text/css" />
<title>Ejemplo uso AJAX en JSF</title>
</h:head>
<h:body>
<header id="cabecera">
<h1>Ejemplo uso AJAX en JSF</h1>
</header>
<div class="cuerpo">
<article class="contenido">
<h2 class="titulo-formulario">Formulario AJAX</h2>
<h:form>
<div class="campo-formulario">
<h:outputLabel for="nombre" value="Nombre: "/>
<h:inputText id="nombre" value="#{usuario.nombre}">
<f:ajax event="keyup" render="mensaje-nombre" listener="#{usuario.validarNombre}"/>
</h:inputText>
<h:outputText id="mensaje-nombre" class="mensaje-error" value="#{usuario.mensajeErrorNombre}"/>
</div>
<div class="campo-formulario">
<h:outputLabel for="password" value="Contraseña: "/>
<h:inputSecret id="password" value="#{usuario.password}">
<f:ajax render="mensaje-password" listener="#{usuario.validarPassword}"/>
</h:inputSecret>
<h:outputText id="mensaje-password" class="mensaje-error" value="#{usuario.mensajeErrorPassword}"/>
</div>
<div class="campo-formulario">
<h:outputLabel for="edad" value="Edad: "/>
<h:inputText id="edad" value="#{usuario.edad}"/>
</div>
<h:commandButton value="Introducir datos">
<f:ajax execute="nombre edad password" render=":saludo :tu-edad :longitud-password"/>
</h:commandButton>
</h:form>
<h:outputText id="saludo" value="Hola #{usuario.nombre}!!!"/>
<br/>
<h:outputText id="tu-edad" value="Tu edad es: #{usuario.edad}"/>
<br/>
<h:outputText id="longitud-password" value="La longitud de tu contraseña es: #{usuario.password.length()}"/>
</article>
</div>
<footer id="pie">
<span id="proyecto">Ejemplos de Ajax con JavaServer Faces.</span>
<span id="autor"><a href="http://programandoointentandolo.com">Iván Salas Corrales</a></span>
</footer>
</h:body>
</html>
Hay 3 elementos en los que se hace una petición Ajax, en el h:inputText, en el h:inputSecret y en el h:commandButton empecemos por el primero.
<h:inputText id="nombre" value="#{usuario.nombre}">
<f:ajax event="keyup" render="mensaje-nombre" listener="#{usuario.validarNombre}"/>
</h:inputText>
<h:outputText id="mensaje-nombre" class="mensaje-error" value="#{usuario.mensajeErrorNombre}"/>
En este caso la petición se realiza cada vez que se deja de pulsar una tecla porque el evento que disparará la llamada es keyup, como resultado de esta pulsación se actualiza únicamente el componente con id mensaje-nombre porque es el que se indica en el atributo render y además de esto también se ejecutará la función validarNombre que aparece como listener, luego veremos esa función en el Managed Bean.
En el caso de la password no hay indicado ningún evento por lo que se ejecutará cuando ocurra el evento predefinido para los inputs y selects que es valueChange, asique en este caso la petición se hace cuando se modifica el contenido del inputSecret y se pierde el foco ya sea haciendo click fuera de él, pulsando enter o usando el tabulador.
<h:inputSecret id="password" value="#{usuario.password}">
<f:ajax render="mensaje-password" listener="#{usuario.validarPassword}"/>
</h:inputSecret>
<h:outputText id="mensaje-password" class="mensaje-error" value="#{usuario.mensajeErrorPassword}"/>
La ultima llamada es la del commandButton, en este caso tampoco se indica ningún evento ni tampoco ningún listener pero si tiene el atributo execute mediante el cual se indica que se envíen los componentes con ids nombre, edad y password al servidor para actualizar sus datos.
En los 2 casos anteriores los componentes indicados en el atributo render de f:ajax están dentro del h:form en el que se encuentra la petición Ajax, pero si los componentes estuviesen fuera de un h:form JSF no los encuentra si solo se indica su id por lo que hay que poner dos puntos (:) delante del id del elemento que se quiere actualizar como ocurre en este ultimo caso.
<h:commandButton value="Introducir datos">
<f:ajax execute="nombre edad password" render=":saludo :edad :longitud-password"/>
</h:commandButton>
</h:form>
<h:outputText id="saludo" value="Hola #{usuario.nombre}!!!"/>
<br/>
<h:outputText id="tu-edad" value="Tu edad es: #{usuario.edad}"/>
<br/>
<h:outputText id="longitud-password" value="La longitud de tu contraseña es: #{usuario.password.length()}"/>
Una vez vista toda la parte de la vista (el facelet) vamos a ver el Managed Bean del ejemplo:
package beans;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.AjaxBehaviorEvent;
/**
*
* @author Ivan Salas Corrales <http://programandoointentandolo.com/>
*/
@ManagedBean
@RequestScoped
public class Usuario {
private String nombre;
private String password;
private int edad;
private String mensajeErrorNombre;
private String mensajeErrorPassword;
/**
* Creates a new instance of Usuario
*/
public Usuario() {
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
public String getMensajeErrorPassword() {
return mensajeErrorPassword;
}
public void setMensajeErrorPassword(String mensajeErrorPassword) {
this.mensajeErrorPassword = mensajeErrorPassword;
}
public String getMensajeErrorNombre() {
return mensajeErrorNombre;
}
public void setMensajeErrorNombre(String mensajeErrorNombre) {
this.mensajeErrorNombre = mensajeErrorNombre;
}
/**
* Comprueba que la longitud del nombre este en el rango correcto
*
* @param evento
*/
public void validarNombre(AjaxBehaviorEvent evento) {
if (nombre.length() < 4) {
mensajeErrorNombre = "El nombre tiene que tener como minimo 4 caracteres";
} else {
if (nombre.length() > 10) {
mensajeErrorNombre = "El nombre puede tener como maximo 10 caracteres";
} else {
mensajeErrorNombre = "";
}
}
}
/**
* Comprueba que la longitud de la password este en el rango correcto
*
* @param evento
*/
public void validarPassword(AjaxBehaviorEvent evento) {
if (password.length() < 6) {
mensajeErrorPassword = "La contraseña tiene que tener como minimo 6 caracteres";
} else {
if (password.length() > 15) {
mensajeErrorPassword = "La contraseña puede tener como maximo 15 caracteres";
} else {
mensajeErrorPassword = "";
}
}
}
}
Es un Managed Bean normal y corriente en el que lo único que hay que comentar es que tiene dos métodos escuchadores (validarNombre y validarPassword) que como se puede ver no tienen nada de especial y lo único que nos indica que son listeners es que reciben un atributo del tipo AjaxBehaviorEvent.
Y eso es todo, en los atributos que no he puesto en los ejemplos creo que no hay mucho problema pero si hay alguna duda pues espero vuestros comentarios.
Muy buen ejemplo. Muchas gracias.
Muy buen ejemplo, Gracias!
Esta muy claro. Mil gracias.