Update URL parameters after method call - jsf-2

This should be simple, but I am looking at other questions and I am not able to find the right answer for my issue.
I have a JSF page that calls a method myController.load():
<f:metadata>
<f:viewParam name="id" value="#{myController.id}" required="false"/>
<f:viewAction action="#{myController.load()}" />
This method will generate an id that is placed in myController.id if originally the page was not called with such parameter. My question is how can I make the URL at the navigation bar reflect this change, i.e. insert this new parameter in the URL. Basically:
--> Browse to myPage.xhtml
--> call to myController.load() which sets myController.id = 1
--> Reflect in URL myPage.xhtml?id=1. Ideally without re-loading the page

You will want to do some reading about PRG (Post/Redirect/Get). Here is a good start.
https://mobiarch.wordpress.com/2012/08/09/doing-post-redirect-get-pattern-in-jsf-2/
You'll want your original JSF link to call an ActionListener that will create a scoped reference to myController and set the id attribute to 1 there... then you can use PRG to redirect to your page. PRG will use the value of your bean to build the new URL correctly as you want.
This ActionListener method is very simple just to help illustrate...
// my ActionListener method
public String goToMyPage() {
myController.setId(1); // assuming myController is declared in scope.
return "myPage?faces-redirect=true&includeViewParams=true";
}
Hope this helps get you started.

Related

how to load page from hyperlink in JSF-2.2 [duplicate]

I've read how to send parameters using JSF but what if the user types their companyId in the URL when accessing their login page? For example,
http://my.company.url/productName/login.faces?companyId=acme.
The way we do it now, there is a bit of scriptlet code that grabs the value from the request and then set it in the session. That parameter changes their look and feel starting from the login page forward so each customer could have a different login page view. We are using extjs until I switch over to JSF.
Is there a way to do that using JSF 2 or perhaps PrimeFaces?
Yes, you can use the <f:viewParam> to set a request parameter as a managed bean property.
<f:metadata>
<f:viewParam name="companyId" value="#{bean.companyId}" />
</f:metadata>
You can if necessary invoke a bean action using <f:viewAction> (JSF 2.2+ only) or <f:event type="preRenderView">.
<f:metadata>
<f:viewParam name="companyId" value="#{bean.companyId}" />
<f:viewAction action="#{bean.onload}" />
</f:metadata>
When using <f:viewAction> you can even return a navigation outcome.
public String onload() {
// ...
return "somepage";
}
When not on JSF 2.2 yet, you can use ExternalContext#redirect() for that. See also among others How to perform navigation in preRenderView listener method.
Note that this is not specific to PrimeFaces. It's just part of standard JSF. PrimeFaces is merely a component library which provides enhanced ajax and skinnability support.
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Communication in JSF 2.0 - Processing GET request parameters
#ManagedProperty with request parameter not set in a #Named bean
url paramters can also be treated as request parameters so you can also access through
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()
There is a utility library, OmniFaces which does this out of the box.
#Inject #Param
private String key;
#Inject #Param
private Long id;
You can use the request.getQueryString() if you want to get full query parameter string.

Difference in navigation by action="xyz" and action="#{bean.returnXyz}"

How is navigation from a Facelet page
<p:commandLink action="xyz.xhtml">
or a backing bean
<p:commandLink action="#{bean.redirect}">
public class Bean{
public String redirect(){
.....
return "xyz.xhtml";
}
}
different from each other?
How is navigation from a xhtml page or a backing bean different from each other.
There's no difference. The both examples invoke a POST request and instructs JSF to render the view associated with the given outcome. The backing bean method has the only advantage that it allows you to perform some business logic beforehand or even control the outcome value programmatically.
However, if you don't have any business logic at all and solely want to have an idempotent link to another page, then using a command link is actually a bad practice. Using POST for page-to-page navigation is not user nor SEO friendly. The target page is not bookmarkable (the URL remains the one of the page where the POST form was been submitted to) nor searchbot-crawlable (it is using JavaScript to submit a hidden form).
You should instead use a normal link.
<h:link outcome="xyz.xhtml">
This generates a SEO-friendly <a> element with the full URL in its href and ends up in an user-friendly bookmarkable URL.
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Check out the documentation of p:commandLink here, which says the following for action attribute:
A method expression or a string outcome to process when command is
executed.
Now, as action="xyz.xhtml" returns String xyz.xhtml you're redirected accordingly and for action="#{bean.redirect}" which again returns xyz.xhtml you are again redirected according to the returned String.

Back button functionality in jsf2

Trying to navigate from page 1 to page 3 as well as page 2 to page3.In page3 when I click on back button it should navigate to the appropriate page.Could anyone please help me how to achieve this?
You can achieve this by having a bean which has a field storing the previous page. Then in the third page you can use the value of this field to return to the appropriate page. For example in your first page you need to have a commandLink navigating you to third page, while setting the previousPage as firstPage. Similar commandLink should be part of second page too. You need to enclose h:commandLinks in h:forms as they use post method to pass parameters.
<h:commandLink value="Third Page" action="#{navigationPageBean.updateLastVisitedPage("/firstPage.xhtml")}"/>
<h:commandLink value="Third Page" action="#{navigationPageBean.updateLastVisitedPage("/secondPage.xhtml")}"/>
#Named
public class NavigationPageBean implements Serializable
{
private String previousPage;
public String updateLastVisitedPage(String pageName)
{
previousPage = pageName;
return "/thirdpage.xhtml";
}
public String getPreviousPage()
{
return previousPage;
}
public void setPreviousPage(String previousPage)
{
this.previousPage = previousPage;
}
}
You can achieve this by using javascript methods to learn the previous page too I think, but I don't know the exact methods.
You have to implement url based navigation if you want to achieve that. To navigate from 1 to 3 you can implement an <h:button> with an outcome attribute.
<h:button value="Go to third" outcome="/thirdpage.xhtml" />
You can also do it specifying navigation rules. However you have dozens of tutorials to do this.
http://www.mkyong.com/jsf2/jsf-2-button-and-commandbutton-example/
http://www.mkyong.com/jsf2/implicit-navigation-in-jsf-2-0/
JSF 2.0 implicit navigation, different views
In order to know where are you coming from there are different ways, but I think the right one is to use view params. In a button or link you can specify an <f:param name="ComingFrom" value="#{sourceBean.id}" /> and you receive it in the destination page that way <f:viewParam id="ComingFrom" name="ComingFrom"
value="#{destinationBean._ParamSourceId}" />.
That way you are passing parameters through the request and you can build your back button to point an url or the other one.
There you have more stuff.
https://blogs.oracle.com/rlubke/entry/jsf_2_0_bookmarability_view

How to get a POST request parameter with a bean managed by CDI?

With requestscoped beans managed by JSF (#Managedbean) you can get the value of a request parameter with #ManagedProperty("#{param.id}").
If the request is a GET request, you can get the value of a request parameter with f:viewParam.
Is there a special mechanism to get the value of a request parameter when the bean is CDI managed (#Named) and the request is a POST request? I only know the Java code
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
The <f:viewParam> works as good in POST requests.
You should only keep in mind that this runs during apply request values phase only, not during render response phase. So, if you're actually navigating on an action method and expecting the parameter to be set as view parameter of the target page, then you're wrong. It will only be set on the view where the POST request is actually submitting to.
As an evidence that the <f:viewParam> works on POST as well, here's a test snippet:
<f:metadata>
<f:viewParam name="foo" />
</f:metadata>
<h:form>
<h:commandButton value="submit">
<f:param name="foo" value="bar" />
</h:commandButton>
</h:form>
<p>foo: #{foo}</p>
Pressing the submit button will show up foo: bar.
You need to solve your concrete functional requirement in a different manner. As you didn't tell anything about the concrete functional requirement in your question, it's not possible to give an elaborate answer on that. Here are at least some hints:
#Inject target bean and set it as property during action method.
Use <f:setPropertyActionListener>.
Use flash scope.
Send a redirect with parameter in query string.

Is there any way to have a bean in ViewScope and RequestScope at same time

I have a table of Items, and in each row there is a link that forwards to the edit item page. To load data in the edit page I need the managed bean in request scope (if I put it in view scope I loose data in the forward).
To use ajax in the edit page I need the managed bean in view Scope due to some values I must keep. If I were working with JSF 1.0 and RichFaces I would do it with request scope and a4j:keepalive.
How do I get this funcionality with PrimeFaces and JSF 2.0 or how can I redefine the interface to get this?
Ok, finally based on the post below this is what worked for me:
CommandButton in the Items table:
<o:commandButton id="editButton"
action="#{itemTableMB.editItem(item.id)}" styleClass="botonTabla">
<h:graphicImage styleClass="imagenBotonTabla" url="/resources/images/icons/pencil.png"/>
</o:commandButton>
Action in the managed bean:
public String editItem(Integer id){
return "/pages/items/edit.xhtml?faces-redirect=true&id="+id;
}
edit.xhtml:
<f:metadata>
<f:viewParam id="id" name="id" value="#{itemMB.item.id}" required="true">
</f:viewParam>
<f:event type="preRenderView" listener="#{itemMB.loadItem}" />
</f:metadata>
Listener in itemMB:
public void loadItem(){
this.item = this.itemManager.get(this.item.getId());
}
To load data in the edit page I need the managed bean in Request scope (If I put it in view scope I loose data in the forward).
Are you using a navigation rule (or implicit navigation) without a redirect?
One solution would be to put backing beans of both the "table of items"-page and the "edit item"-page in view scope, and then go from the first to the second one directly via a GET request (e.g. using <h:link>) or a POST/redirect with a request parameter representing the row on which the user clicked.
Use <f:viewParam> on the second page to conveniently convert the request parameter back to an entity representing the item being edited.
If you were indeed using navigation without redirect, then this has the additional benefit that you won't suffer from the notorious 'one-URL-behind-problem', which can be rather confusing to users of your application and be a nightmare for support.

Resources