How to redirect to an anchor in JSF?
Let's say I have this action in a JSF Managed Bean:
public String doSomething() {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("msg", "Something was done successfully");
return "view?faces-redirect=true";
}
My view
has an anchor element with the id msg
. I want the url to have this anchor (for accessibility matters), like:
view.jsf#msg
Or whatever is my FacesServlet filter pattern.
return "view#msg?faces-redirect=true";
obviously will not work because JSF (mojarra at least) will try to evaluate view#msg
as a view.
So my question is how to m开发者_运维问答ake JSF redirect to a URL with #msg
in the end.
because JSF (mojarra at least) will try to evaluate
view#msg
as a view
Oh, that's nasty. It's definitely worth an enhancement request at the JSF/Mojarra boys.
Your best bet is to send the redirect manually with help of 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");
}
(assuming that FacesServlet
is mapped on *.xhtml
)
Alternatively, you could conditionally render a piece of JS which does that instead.
<ui:fragment rendered="#{not empty flash.msg}">
<script>window.location.hash = 'msg';</script>
</ui:fragment>
You try to build an illegal URL - the fragment (#
) is always the last part of an URL.
return "view?faces-redirect=true#msg"
would be the correct URL.
Unfortunately that fragment is stripped by the default NavigationHandler
, at least in JSF 2.2.
While the two options of BalusC are working as well, I have a third option to offer. Wrap the NavigationHandler
and ViewHandler
with a small patch:
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;
}
}
(I had to create the wrapper for the ViewHandler anyway, because of a fix for JAVASERVERFACES-3154)
精彩评论