开发者

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)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜