2011-07-06 42 views
7

Digamos que tengo esta acción en una JSF Managed Bean:Cómo redirigir a un ancla en JSF?

public String doSomething() { 
    FacesContext.getCurrentInstance().getExternalContext().getFlash().put("msg", "Something was done successfully"); 
    return "view?faces-redirect=true"; 
} 

Mi view tiene un elemento de anclaje con el id msg. Quiero que el url para tener este anclaje (por cuestiones de accesibilidad), como:

view.jsf#msg 

O lo que es mi patrón de filtro FacesServlet.

return "view#msg?faces-redirect=true"; obviamente no funcionará porque JSF (al menos mojarra) intentará evaluar view#msg como una vista.

Así que mi pregunta es cómo hacer que JSF redirija a una URL con #msg al final.

Respuesta

10

porque JSF (mojarra al menos) tratará de evaluar view#msg como una vista

Oh, eso es desagradable. Definitivamente vale la pena una solicitud de mejora en los chicos de JSF/Mojarra.

Su mejor opción es enviar el redireccionamiento manualmente con la ayuda de ExternalContext#redirect().

public void doSomething() throws IOException { 
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
    ec.getFlash().put("msg", "Something was done successfully"); 
    ec.redirect("view.xhtml#msg"); 
} 

(asumiendo que FacesServlet está mapeado en *.xhtml)

Como alternativa, puede hacer que condicionalmente una pieza de JS lo que hace que su lugar.

<ui:fragment rendered="#{not empty flash.msg}"> 
    <script>window.location.hash = 'msg';</script> 
</ui:fragment> 
+1

buena idea de que pedazo de JS. Además, 'ExternalContext # redirect()' funciona en gran medida. Una vez más, una buena respuesta :) – bluefoot

0

intenta generar una URL ilegal - el fragmento (#) es siempre la última parte de una dirección URL.

return "view?faces-redirect=true#msg" sería la URL correcta.

Desafortunadamente ese fragmento se elimina por defecto NavigationHandler, al menos en JSF 2.2.

Si bien las dos opciones de BalusC también funcionan, tengo una tercera opción para ofrecer. Envolver el NavigationHandler y ViewHandler con un pequeño parche:

public class MyViewHandler extends ViewHandlerWrapper { 

    public static final String REDIRECT_FRAGMENT_ATTRIBUTE = MyViewHandler.class.getSimpleName() + ".redirect.fragment"; 

    // ... Constructor and getter snipped ... 

    public String getRedirectURL(final FacesContext context, final String viewId, final Map<String, List<String>> parameters, final boolean includeViewParams) { 
     final String redirectURL = super.getRedirectURL(context, viewId, removeNulls(parameters), includeViewParams); 
     final Object fragment = context.getAttributes().get(REDIRECT_FRAGMENT_ATTRIBUTE); 
     return fragment == null ? redirectURL : redirectURL + fragment; 
    } 

} 

public class MyNavigationHandler extends ConfigurableNavigationHandlerWrapper { 

    // ... Constructor and getter snipped ... 

    public void handleNavigation(final FacesContext context, final String fromAction, final String outcome) { 
     super.handleNavigation(context, fromAction, 
      storeFragment(context, outcome)); 
    } 

    public void handleNavigation(final FacesContext context, final String fromAction, final String outcome, final String toFlowDocumentId) { 
     super.handleNavigation(context, fromAction, 
      storeFragment(context, outcome), toFlowDocumentId); 
    } 

    private static String storeFragment(final FacesContext context, final String outcome) { 
     if (outcome != null) { 
      final int hash = outcome.lastIndexOf('#'); 
      if (hash >= 0 && hash + 1 < outcome.length() && outcome.charAt(hash + 1) != '{') { 
       context.getAttributes().put(MyViewHandler.REDIRECT_FRAGMENT_ATTRIBUTE, outcome.substring(hash)); 
       return outcome.substring(0, hash); 
      } 
     } 
     return outcome; 
    } 
} 

(tuve que crear el contenedor para el ViewHandler todos modos, porque de una solución para JAVASERVERFACES-3154)

Cuestiones relacionadas