Navegar a un enlace interno tras un action en JSF

En este post voy a dar una solución a un problema común que consiste en navegar a un enlace interno tras pulsar en un botón o en un enlace que ejecuta una acción en el servidor.

Si simplemente quisiéramos navegar a un enlace interno sin ejecutar nada en el servidor podríamos hacerlo con un outputLink:

<h:outputLink value="pagina.jsf#ancla" ><h:outputText value="Ir a la página"/> </h:outputLink>

Sin embargo, puede que lo que necesitemos es ejecutar un método en el servidor y luego navegar hacia un ancla. Esto podemos hacerlo con un método actionListener al que enviaremos el nombre del ancla y que se encargará de redireccionar al usuario al ancla especificada tras hacer su trabajo.

En primer lugar veamos el código JSF que incluiría la llamada al actionListener:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<f:view>
<html lang='es'>
<head>
<title>Mi página</title>
<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' />
</head>
<body>
<div id='contenedor'>
<h:form>
<h:commandLink actionListener="#{bean.navegaEnlace}">
<h:outputText value="Ver resultados" />
<f:param name="ancla" value="resultado" />
</h:commandLink>
</h:form>
</div>




<p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p>





<div id='capaResultados'>
<h1><a name='resultado'>Resultados</a></h1>
<h:dataTable id="tablaResultados" value="#{bean.resultados}"
var="resultado" style="width: 100%">
<h:column><h:outputText value="#{resultado}" /></h:column>
</h:dataTable>
</div>




<p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p>  





</body>
</html>
</f:view>


Se han añadido los saltos de línea para comprobar mejor cómo se realiza la navegación al enlace interno. A continuación vemos el código de nuestro bean:

package org.ffbeltran.prueba;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

public class BeanNavegacion {

private List<String> resultados;

public void navegaEnlace(ActionEvent actionEvent) {

resultados = new ArrayList<String>();
for(int i=1;i<11;i  )
resultados.add("Resultado "   i);

// Para recuperar el parámetro enviado por el JSP
String ancla = FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap().get("ancla");

try {
FacesContext.getCurrentInstance().getExternalContext()
.redirect("navegacion.jsf#"+ancla);
} catch (IOException e) {
e.printStackTrace();
}
}

public List<String> getResultados() {
return resultados;
}

}


Como puede observarse, el método navegaEnlace del bean inicializa el array de resultados, recupera el valor del ancla y redirecciona a la misma página pero pasándole el enlace interno.

Este bean debería estar disponible para el contexto de JSF, por ejemplo mediante el siguiente código en el fichero faces-config.xml:

<?xml version="1.0"?>

<faces-config version="1.2" 
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">

<!-- managed beans of the simple hello world app -->
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>org.ffbeltran.prueba.BeanNavegacion</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>

</faces-config>


Esta es la única solución que he encontrado para hacer una navegación interna a un ancla (o anchor) tras ejecutar un método del servidor. El problema es que la redirección se salta el ciclo de JSF por lo que no tenemos las reglas de navegación y algunas cosas pueden no funcionar igual. Si conoces una solución mejor, por favor, coméntalo en el post.

0 comentarios:

Publicar un comentario