Back button functionality in jsf2 - jsf-2

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

Related

Update URL parameters after method call

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.

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.

Change commandLink Id by my code in datatable

I need a way to manage the creation of the commandlink ID in DataTable, the problem is that when i use it for deleting a record and interrupt the rendering of the page (reloading it by 'ctrl+f5' ) it assigns the same id to another link button, which results in deleting the row containing it.
The problem in question is sound, but the requested solution is not the right one and not easily to achieve in JSF — basically, you'd need to homebrew a custom command link renderer which is designed specifically for usage in data tables and is able to recognize the specific entity.
The right solution is send a redirect to the same view after POST.
public String delete() {
// ...
return FacesContext.getCurrentInstance().getViewRoot().getViewId() + "?faces-redirect=true"; // Feel free to hardcode the view ID, though.
}
(if you intend to display some faces message along it, use the flash scope)
A browser refresh would then result in only the redirect being refreshed rather than the POST action.
An alternative is to submit by ajax instead.
<h:commandLink ...>
<f:ajax execute="#form" render="#form" />
</h:commandLink>
A browser refresh would then only re-execute the last synchronous request, which would be the initial GET request which opened the page in question.

Dynamic breadcrumbs with primefaces

I would like to add to my web app a dynamic breadcrumb using the Primefaces component. I've created a model to push items on the breadcrumb so that when one of its links is followed, the trailing links are removed. This works in most scenarios, but sometime the bradcrumb doesn't behave the way I expect. Basically, in order to track the landing page, I've added a preRenderView listener on each navigable page and implemented the model update logic in a session scoped bean.
<f:event type="preRenderView" listener="#{bcb.onRenderView}" />
<f:attribute name="pageName" value="ThisPage" />
The listener receives the page name as an attribute and obtains the complete URL (including query string) from the external context; these information, along with a unique id created from the UIViewRoot, are used to build a BreadCrumbItem that is pushed on the model:
public void onRenderView(ComponentSystemEvent evt) {
UIViewRoot root = (UIViewRoot)evt.getSource();
final String reqUrl = FacesUtils.getFullRequestURL();
String pageName = (String) evt.getComponent().getAttributes().get("pageName");
if(pageName != null) {
model.push(new BreadCrumbItem(root.createUniqueId(), pageName, reqUrl));
} else {
model.reset();
}
}
The push() and reset() methods of the model are implemented as follows:
/**
* When a link is pushed on the bread crumb, the existing items are analyzed
* and if one is found to be equal to the pushed one, the link is not added
* and all the subsequent links are removed from the list.
*
* #param link
* the link to be added to the bread crumb
*/
public void push(BreadCrumbItem link) {
boolean found = removeTrailing(link);
if(!found) {
addMenuItem(link);
}
}
/**
* Reset the model to its initial state. Only the home link is retained.
*/
public void reset() {
BreadCrumbItem home = new BreadCrumbItem();
removeTrailing(home);
}
Is this approach feasible? Can you suggest some better way to track page navigation without the need to leverage a life cycle listener? Thanks a lot for your help.
I have implemented my own one for my web app, in my case I didn't use the p:breadCrumb component because it's implemented using buttons.
Basically, I have an #SessionScoped bean which contains a stack (navigation stack), storing all the url's you have in the breadcrumb and the params for each of them. The view (xhtml) part is composed by p:button elements, which have the outcome of the stack's stored urls.
When you navigate to an url, corresponding bean's f:event type="preRenderView" is called (as the way you're doing it) and the bean takes the params from the url, after that it establishes itself into the stack (not the bean itself, cause it's #ViewScoped and going to be destroyed, just the url and params).
In case you click on a back button in the breadcrum, you send an additional param which indicates the index of the button. Based on that index, the destination bean knows that you're trying to recover such view, so asks the navigation stack for that view params and navigation stack removes navegables which are after it.
It took me a while, but it's fully functional. Good luck.
Edit
Be careful when using session scope for saving the current navigation state. It'll have influence in all the opened tabs, so probably it's not what you want, unless you expect your end user to use your application in one tab only. Anyway, the general usability guidelines say you should use categories instead of navigation paths for your breadcrumbs (HTTP is stateless and the history itself is kept by the browser). So a dynamic breadcrumb doesn't make sense anymore, at least if you're using different urls for your views.

hide an attribute initially at startup in web application

I am working on a JSF application.
I have recently faced a problem, that how to hide any attribute at the start-up of the application.
For Example -
I have a h:panelGrid attribute for displaying table, but I want to show this table only when a checkbox is clicked, Here I am able to made it working for show/hide but only from second time onwards.
What I want is to hide this table using h:panelGrid when application loads this view, the later part as I told I have achieved.
It would be grateful if somebody cite it for general hide at start-up.
Thanks.
Create a boolean attribute in the ManagedBean which this page uses and set it to false (for example in PostConstruct method). Then use it as a rendered attribute of your <h:panelGrid> and it's going to be defaultly hidden.
let's say
#ManagedBean
#RequestScoped
public class Bean {
private boolean visible = false;
//setters and getters
}
//later on page
<h:panelGrid rendered="#{bean.visible} />
I got it...somehow like this
in panelGrid set style="visibility:hidden"
and in checkBox, call javascript function and in there set
if (show)
{
obj.style.display = "block";
obj.style.visibility="visible";
}
else
{
obj.style.display = "none";
}
It does the trick.
Thanks Petr for help.

Resources