custom navigation handler - handleNavigation not invoked by h:link - jsf

The handle navigation method handleNavigation(final FacesContext context, final String fromAction, final String outcome) from my custom navigation handler is not invoked by my h:link component?
<h:link value="text" outcome="./target.xhtml?faces-redirect=true">
<f:param name="param" value="#{var.prop}"/>
</h:link>
Using commandbutton invokes it.

The <h:link> doesn't send a POST request whereafter the target URL is been resolved. Instead, the <h:link> generates a HTML <a> element with the target URL already right in there in the href attribute which is in turn to be used to send a GET request. This URL is obtained by ViewHandler#getBookmarkableURL(), which in turn delegates to ViewHandler#getActionURL().
If you're using Mojarra, you can see all the job in OutcomeTargetLinkRenderer#renderAsActive().
You can easily provide a custom ViewHandler by extending ViewHandlerWrapper and registering it as <application><view-handler>.

Related

jsf page navigation best practices [duplicate]

When should I use an <h:outputLink> instead of an <h:commandLink>?
I understand that a commandLink generates an HTTP post; I'm guessing that outputLink will generate HTTP gets. That said, most of the JSF tutorial material I've read uses commandLink (almost?) exclusively.
Context: I am implementing a wee little demo project that shows a header link to a user page, much like Stack Overflow's...
...and I am not sure if commandLink (perhaps using ?faces-redirect=true for bookmarkability) or outputLink is the right choice.
The <h:outputLink> renders a fullworthy HTML <a> element with the proper URL in the href attribute which fires a bookmarkable GET request. It cannot directly invoke a managed bean action method.
<h:outputLink value="destination.xhtml">link text</h:outputLink>
The <h:commandLink> renders a HTML <a> element with an onclick script which submits a (hidden) POST form and can invoke a managed bean action method. It's also required to be placed inside a <h:form>.
<h:form>
<h:commandLink value="link text" action="destination" />
</h:form>
The ?faces-redirect=true parameter on the <h:commandLink>, which triggers a redirect after the POST (as per the Post-Redirect-Get pattern), only improves bookmarkability of the target page when the link is actually clicked (the URL won't be "one behind" anymore), but it doesn't change the href of the <a> element to be a fullworthy URL. It still remains #.
<h:form>
<h:commandLink value="link text" action="destination?faces-redirect=true" />
</h:form>
Since JSF 2.0, there's also the <h:link> which can take a view ID (a navigation case outcome) instead of an URL. It will generate a HTML <a> element as well with the proper URL in href.
<h:link value="link text" outcome="destination" />
So, if it's for pure and bookmarkable page-to-page navigation like the SO username link, then use <h:outputLink> or <h:link>. That's also better for SEO since bots usually doesn't cipher POST forms nor JS code. Also, UX will be improved as the pages are now bookmarkable and the URL is not "one behind" anymore.
When necessary, you can do the preprocessing job in the constructor or #PostConstruct of a #RequestScoped or #ViewScoped #ManagedBean which is attached to the destination page in question. You can make use of #ManagedProperty or <f:viewParam> to set GET parameters as bean properties.
See also:
ViewParam vs #ManagedProperty(value = "#{param.id}")
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Bookmarkability via View Parameters feature
How to navigate in JSF? How to make URL reflect current page (and not previous one)
I also see that the page loading (performance) takes a long time on using h:commandLink than h:link. h:link is faster compared to h:commandLink

Bean's method that returns to the previous page

After performing the appropriate action, the method of my bean must ensure that the browser back to the previous page. How can I handle it?
I am using the CDI Conversation.
Pass the current URI as request parameter along during navigation to the page containing that action.
<h:link value="Go to page containing that action" outcome="pageContainingThatAction.xhtml">
<f:param name="from" value="#{request.requestURI}" />
</h:link>
(use #{view.viewId} instead if you want to pass the view ID)
Set and remember that parameter representing the URI in the view/conversation scoped managed bean.
<f:metadata>
<f:viewParam name="from" value="#{bean.from}" />
</f:metadata>
Finally redirect to that URI in that action method.
public void thatActionMethod() throws IOException {
// ...
externalContext.redirect(from);
}
After asking you a couple of question in comments, I think what you want to do is :
On your button, specify the attribute action to a function in your bean that return a String.
The String returned need to be the navigation path to the page you want to be redirected.
If the validation is wrong on button click, then simply return null and it will stay on same page.
Make sure you define the proper navigation rule in faces-config.xml
See this tutorial for how to configure navigation rules.
See Primefaces commandButton doc for info on action tag.

commandLink is not fired in a page with a param in its URI

When I call a method in a page with a param in its URI, the method is not invoked unless I pass the parameters of the uri again. For example if I have:
http://maywebsite/myapp/mypage.xhtml?mykey=myvalue
This method results in error (obviously because it renders the page again without params, but the method foo is never invoked):
<h:commandLink value="Do Action" actionListener="#{mybean.foo}"/>
So I added an ajax to only update the component, but the button is not getting fired:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:ajax render="somecomponent"/>
</h:commandLink>
When I passed the param values again, the button invokes the method just fine:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:param name="mykey" value="myvalue"/>
<f:ajax render="somecomponent"/>
</h:commandLink>
However, this button is included (ui:include) in many pages with different param keys and values. How can I invoke the method without passing the param values?
Im using glassfish 3.1.2, jsf 2.0
Apparently the bean is request scoped and the parameter plays a role in the way how the command link is rendered (e.g. by the rendered attribute on one of its parent components, or by a dynamic include of the template containing the command link).
All those conditions are namely re-evaluated during apply request values phase of the form submit. The developer has to make sure that all those conditions are exactly the same as when the form was presented to the enduser. So, when the bean is request scoped and the parameter is absent, then the command link appears as non-rendered in the component tree and this way its action won't be invoked.
Putting the bean in the view scope is the easiest way to fix this (unless you're using a dynamic <ui:include>, this is then more complicated, you'd need to turn off partial state saving for the particular view).
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5

JSF request attribute

I am using JSF 1.2. I have a page with a button. The action hooked to the button adds a request attribute to the request object and navigates to page2. On page2 I try to retrieve that attribute with #{requestScope.attr}. But this doesn't work. Any ideas why?
Thx.
Apparently page2 was requested by a different HTTP request. That can happen if you have sent a redirect instead of a forward when the action method is finished. For example, by calling ExternalContext#redirect() in the action method or by adding <redirect /> to the navigation case. A redirect basically instructs the browser to create a brand new HTTP request.
That said, I wonder how it's useful to explicitly set a request attribute if you're already using JSF. Just assign the desired data as a property of the current bean (which I assume to be just request scoped).
private String foo; // +getter
public String submit() {
foo = "some value";
return "nextpage";
}
This way it's just available by #{bean.foo} in the next page.
<h:outputText value="The value is: #{bean.foo}" />

When should I use h:outputLink instead of h:commandLink?

When should I use an <h:outputLink> instead of an <h:commandLink>?
I understand that a commandLink generates an HTTP post; I'm guessing that outputLink will generate HTTP gets. That said, most of the JSF tutorial material I've read uses commandLink (almost?) exclusively.
Context: I am implementing a wee little demo project that shows a header link to a user page, much like Stack Overflow's...
...and I am not sure if commandLink (perhaps using ?faces-redirect=true for bookmarkability) or outputLink is the right choice.
The <h:outputLink> renders a fullworthy HTML <a> element with the proper URL in the href attribute which fires a bookmarkable GET request. It cannot directly invoke a managed bean action method.
<h:outputLink value="destination.xhtml">link text</h:outputLink>
The <h:commandLink> renders a HTML <a> element with an onclick script which submits a (hidden) POST form and can invoke a managed bean action method. It's also required to be placed inside a <h:form>.
<h:form>
<h:commandLink value="link text" action="destination" />
</h:form>
The ?faces-redirect=true parameter on the <h:commandLink>, which triggers a redirect after the POST (as per the Post-Redirect-Get pattern), only improves bookmarkability of the target page when the link is actually clicked (the URL won't be "one behind" anymore), but it doesn't change the href of the <a> element to be a fullworthy URL. It still remains #.
<h:form>
<h:commandLink value="link text" action="destination?faces-redirect=true" />
</h:form>
Since JSF 2.0, there's also the <h:link> which can take a view ID (a navigation case outcome) instead of an URL. It will generate a HTML <a> element as well with the proper URL in href.
<h:link value="link text" outcome="destination" />
So, if it's for pure and bookmarkable page-to-page navigation like the SO username link, then use <h:outputLink> or <h:link>. That's also better for SEO since bots usually doesn't cipher POST forms nor JS code. Also, UX will be improved as the pages are now bookmarkable and the URL is not "one behind" anymore.
When necessary, you can do the preprocessing job in the constructor or #PostConstruct of a #RequestScoped or #ViewScoped #ManagedBean which is attached to the destination page in question. You can make use of #ManagedProperty or <f:viewParam> to set GET parameters as bean properties.
See also:
ViewParam vs #ManagedProperty(value = "#{param.id}")
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Bookmarkability via View Parameters feature
How to navigate in JSF? How to make URL reflect current page (and not previous one)
I also see that the page loading (performance) takes a long time on using h:commandLink than h:link. h:link is faster compared to h:commandLink

Resources