11

A Redirect from Bean in JSF can be done by

externalContext.redirect("foo.xhtml");

But I want to use the rules, set in <navigation-rule/> (faces-config.xml) for <from-outcome/> && pass command line arguments.

externalContext.redirect("from-outcome?param=bar");

Is not working. How to do that?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
timmornYE
  • 708
  • 2
  • 8
  • 22

1 Answers1

17

The ExternalContext#redirect() takes an URL, not a navigation outcome.

You need to return navigation outcomes from action methods declared to return String.

public String submit() {
    // ...

    return "from-outcome";
}

You can configure the navigation case to send a redirect by adding <redirect>.

<navigation-rule>
    <navigation-case>
        <from-outcome>from-outcome</from-outcome>
        <to-view-id>/foo.xhtml</to-view-id>
        <redirect>
            <view-param>
                <name>param</name>
                <value>bar</value>
            </view-param>
        </redirect>
    </navigation-case>
</navigation-rule>

Note that you can also just make use of JSF implicit navigation without the need for this XML mess:

public String submit() {
    // ...

    return "/foo.xhtml?faces-redirect=true&param=bar";
}

If you're inside an event or ajax listener method which can't return a string outcome, then you could always grab NavigationHandler#handleNavigation() to perform the desired navigation.

public void someEventListener(SomeEvent event) { // AjaxBehaviorEvent or ComponentSystemEvent or even just argumentless.
    // ...

    FacesContext context = FacesContext.getCurrentInstance();
    NavigationHandler navigationHandler = context.getApplication().getNavigationHandler();
    navigationHandler.handleNavigation(context, null, "from-outcome");
}

The non-navigation-case equivalent for that is using ExternalContext#redirect().

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    Thanks @BalusC, but how do I modify the value in the navigation-rule from the bean? – timmornYE Aug 30 '13 at 05:12
  • 1
    You can use EL in `` like so `#{bean.param}`. This is equivalent to `return "/foo.xhtml?faces-redirect=true&param=" + URLEncoder.encode(param, "UTF-8");` (although some Mojarra versions have bugs with charset being used). – BalusC Aug 30 '13 at 10:38
  • Thanks, I understand. But to come back to my question: So there is no way to use `navigation-rule` without returning a String? Because there are situations where this is not possible. What to do, if I want redirect from an Ajax call? There I can not return the navigation as String or am I wrong? – timmornYE Aug 30 '13 at 13:27
  • Use `ExternalContext#redirect()` with a true URL then. You can convert a navigation outcome to a true URL using `ViewHandler#getBookmarkableURL()`. – BalusC Aug 30 '13 at 13:28
  • If I give a value of `from-outcome` to `ViewHandler#getBookmarkableURL()` I get a `IllegalArgumentException`. It says, it has to start with "/". but if I do so, the navigation rule is not used. Perhaps I should start a new question and show what I did? Thank you very much for help! – timmornYE Aug 30 '13 at 13:51
  • 1
    Sorry, I seriously mixed up things here (I'm a fan of implicit navigation where view ID is exactly the same as outcome, which eliminates code duplication; I never really used XML navigation cases, `getBookmarkableURL()` takes a view ID, not an XML outcome), you should use `NavigationHandler#handleNavigation()`. Examples: http://stackoverflow.com/questions/13530651/jsf-call-backing-bean-method-without-rendering-the-page-using-url-parameters/13530836#13530836 and http://stackoverflow.com/questions/8255472/jsf-primefaces-selectonemenu-change-view-id/8256339#8256339 – BalusC Aug 30 '13 at 13:54
  • I updated the answer with an example specifically for your case. – BalusC Aug 30 '13 at 13:59
  • Thank you very much. That does the job! Now one last thing would be open, then this answer copes all needs I think: How do I get the navigation outcome as string? So like `ViewHandler#getBookmarkableURL()` but with a navigation rule, not view ID. This is for example needed, if I use primefaces `DefaultTagCloudItem`. It takes the URL as String for the Tag Cloud. – timmornYE Aug 30 '13 at 14:54
  • 1
    Cast `Application#getNavigationHandler()` to `ConfigurableNavigationHandler`, then you'll be able to call `getNavigationCase()` on it which in turn has among others `getBookmarkableURL()`. – BalusC Aug 30 '13 at 14:59
  • Works like a charm. Many thanks, I think now I can handle all navigation related tasks! – timmornYE Aug 30 '13 at 19:57
  • With no parameters being included in redirect, just add `` to the `` node. – Roland Apr 24 '20 at 02:20