jsf navigation facelets breadcrumbs

JSF/Facelets: establece el atributo `action` en una cadena evaluada dinĂ¡micamente



navigation breadcrumbs (3)

En mi aplicación JSF / Facelets, quiero generar dinámicamente un rastro de navegación de una lista de ID de página usando una etiqueta personalizada:

<foo:breadcrumbs trail="foo,bar,baz"/>

Esto debería generar algo como:

<h:commandLink action="foo" ... /> <h:commandLink action="bar" ... /> <!-- (etc.) -->

Mi código se ve así:

<ui:repeat value="#{fn:split(trail, '','')}" var="key"> <h:commandLink action="#{key}" ... /> </ui:repeat>

El problema con este código es que #{key} se interpreta como un enlace de método. Sin embargo, solo quiero que se devuelva el valor de cadena de #{key} como resultado de navegación. ¿Cómo puedo conseguir esto?

Lo único que se me ocurrió fue crear un frijol administrado ficticio que tuviera un campo de outcome y un manejador de acciones, e invocarlo así:

<h:commandLink action="#{dummy.click}" ...> <f:setPropertyActionListener target="#{dummy.outcome}" value="#{key}" /> </h:commandLink>

con la clase ficticia definida así:

public class Dummy { private String outcome; public String click() { return outcome; } public void setOutcome(String outcome) { this.outcome = outcome; } public void getOutcome() { return outcome; } }

Eso parece feo, y no sé si funcionaría.


¿Por qué no creas un componente personalizado que genere los objetos h: commandLink programáticamente? Probablemente sea la solución más "limpia".


Desde que hice esta pregunta, descubrí una solución obvia que es muy simple de implementar.

Un método que es el objetivo de una acción JSF no debe aceptar argumentos y devolver un String. ¡Resulta que la clase String ya tiene un método que coincide con esta firma - toString() !

Entonces, cambié mi bucle de UI a lo siguiente:

<ui:repeat value="#{fn:split(trail, '','')}" var="key"> <h:commandLink action="#{key.toString}" ... /> </ui:repeat>

Esto permite que la key evaluada dinámicamente sea el resultado de la acción JSF, y no requiere ninguna clase adicional o piratería fea.


Un par de formas me vienen a la mente.

Opción 1

Sigue con commandLink y lee la var directamente desde el mapa de solicitud en el enlace de acción:

public String click() { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext extContext = context.getExternalContext(); Map<String, Object> reqMap = extContext.getRequestMap(); return (String) reqMap.get("uirepeatVar"); }

(Donde el repetidor tiene el atributo var="uirepeatVar" )

opcion 2

Cambie a un enlace de salida y cree enlaces GET en el servidor:

public List<String> getViewUrls() { List<String> views = Arrays.asList("/index.xhtml", "/idtable.xhtml"); List<String> urls = new ArrayList<String>(); FacesContext context = FacesContext.getCurrentInstance(); Application application = context.getApplication(); ViewHandler viewHandler = application.getViewHandler(); for (String view : views) { String url = viewHandler.getActionURL(context, view); urls.add(url); } return urls; }

Ver:

<ui:repeat value="#{breadcrumbBean.viewUrls}" var="url"> <h:outputLink value="#{url}">#{url}</h:outputLink> <br /> </ui:repeat>