jsf 2 - navegacion - Migas de pan dinámicas con materias primas
primefaces showcase (1)
Me gustaría agregar a mi aplicación web una ruta de exploración dinámica utilizando el componente Primefaces. Creé un modelo para insertar elementos en la ruta de navegación, de modo que cuando se sigue uno de sus enlaces, se eliminan los enlaces finales. Esto funciona en la mayoría de los escenarios, pero en algún momento la ruta de acceso no se comporta de la manera que yo esperaba. Básicamente, para rastrear la página de inicio, agregué un oyente preRenderView
en cada página navegable e implementé la lógica de actualización del modelo en un bean con ámbito de sesión.
<f:event type="preRenderView" listener="#{bcb.onRenderView}" />
<f:attribute name="pageName" value="ThisPage" />
El oyente recibe el nombre de la página como un atributo y obtiene la URL completa (incluida la cadena de consulta) del contexto externo; esta información, junto con un ID único creado a partir de UIViewRoot
, se utiliza para construir un BreadCrumbItem
que se inserta en el modelo:
public void onRenderView(ComponentSystemEvent evt) {
UIViewRoot root = (UIViewRoot)evt.getSource();
final String reqUrl = FacesUtils.getFullRequestURL();
String pageName = (String) evt.getComponent().getAttributes().get("pageName");
if(pageName != null) {
model.push(new BreadCrumbItem(root.createUniqueId(), pageName, reqUrl));
} else {
model.reset();
}
}
Los métodos push()
y reset()
del modelo se implementan de la siguiente manera:
/**
* When a link is pushed on the bread crumb, the existing items are analyzed
* and if one is found to be equal to the pushed one, the link is not added
* and all the subsequent links are removed from the list.
*
* @param link
* the link to be added to the bread crumb
*/
public void push(BreadCrumbItem link) {
boolean found = removeTrailing(link);
if(!found) {
addMenuItem(link);
}
}
/**
* Reset the model to its initial state. Only the home link is retained.
*/
public void reset() {
BreadCrumbItem home = new BreadCrumbItem();
removeTrailing(home);
}
¿Es este enfoque factible? ¿Puede sugerir alguna forma mejor de seguir la navegación de la página sin la necesidad de aprovechar un oyente de ciclo de vida? Muchas gracias por tu ayuda.
Implementé el mío propio para mi aplicación web, en mi caso no p:breadCrumb
componente p:breadCrumb
porque se implementó usando botones.
Básicamente, tengo un bean @SessionScoped
que contiene una pila (pila de navegación), almacenando todas las url que tienes en la @SessionScoped
navegación y los parámetros para cada una de ellas. La parte view ( xhtml ) está compuesta por elementos p:button
, que tienen el outcome
de las URL almacenadas de la pila.
Cuando navegas hacia una url , se llama a los f:event type="preRenderView"
correspondientes f:event type="preRenderView"
(de la forma en que lo haces) y el bean toma los parámetros de la url, luego se establece en la pila (no el Bean en sí, porque es @ViewScoped
y va a ser destruido, solo la url y los params).
En caso de que haga clic en un botón Atrás en el breadcrum, envíe un parámetro adicional que indique el índice del botón. En función de ese índice, el bean de destino sabe que está tratando de recuperar dicha vista, por lo que le pide a la pila de navegación que los parametros de vista y la pila de navegación elimine los navegables que están detrás de ella.
Me tomó un tiempo, pero es completamente funcional. Buena suerte.
Editar
Tenga cuidado al usar el alcance de sesión para guardar el estado de navegación actual. Tendrá influencia en todas las pestañas abiertas, por lo que probablemente no sea lo que quieres, a menos que esperes que tu usuario final use tu aplicación en una sola pestaña. De todos modos, las pautas generales de usabilidad dicen que debe usar categorías en lugar de rutas de navegación para sus rutas de exploración ( HTTP es sin estado y el historial lo conserva el navegador). Por lo tanto, una ruta de navegación dinámica ya no tiene sentido, al menos si usa diferentes URL para sus vistas.