JSF: Bookmarkability with ViewScoped - jsf

I am trying to make my app "Bookmarkable", and i am using view parameters to achieve it.
And i think i still do not get the right way to do it right in JSF, even after reading this, and many others.
My problem is that the get parameters get lost after any non-ajax postback, i mean, the parameter value is still set in the bean and the app works correctly, but it gets removed from the URL making the URL invalid.
For instance, having an URL like http://company.com/users?id=4, as soon as that page executes a non-ajax postback (for uploading data, for instance) the URL becomes just http://company.com/users. The app continues to work correctly, but the link is not any more "Bookmarkable".
Is there any way to prevent the non-ajax postbacks removing the viewParams from the URL?
My use case is to be able to bookmark a page to EDIT an object, and there i need to be able to upload data (if not i would not use non-ajax postbacks). I know i would not need any postback if i would want to bookmark the page to only VIEW the data of the object, but that is not my case.
I could also do a redirect to the same page with the same params, and let the app to recreate the view scoped bean, but then i really do not see any benefit over request scoped beans...
Any suggestion is very appreciated.

This behaviour is "by design". The <h:form> generates a HTML <form> element with an action URL without any view parameters. The synchronous POST request just submits to exactly that URL which thus get reflected as-is in browser's address bar. If you intend to keep the view parameters in the URL, while using ajax is not an option, then you basically need to create a custom ViewHandler which has the getActionURL() overridden to include the view parameters. This method is used by <h:form> to generate the action URL.
public String getActionURL(FacesContext context, String viewId) {
String originalActionURL = super.getActionURL(context, viewId);
String newActionURL = includeViewParamsIfNecessary(context, originalActionURL);
return newActionURL;
}
Or, as you're based on the comments already using OmniFaces, you could also use its <o:form> component which basically extends the <h:form> with the includeViewParams attribute which works much like the same as in <h:link> and <h:button>.
<o:form includeViewParams="true">
...
</o:form>
This way all <f:viewParam> values will end up in the form action URL.
See also:
Handling view parameters in JSF after post

Related

How to reinit some values in session bean on page load?

i want to make something similar to view scope with the session scope.
i have a session bean, and in my page i have some search result tables, that i want to clear them and clear the input texts on page load, i can't change from session bean to request bean, and my only idea right now is to add a clear button on the page which it's action method would reset the tables and the input texts.
i am using jsf 1.1, please advise about best way to do that.
Check if the request is a GET request (or, at least, not a POST request).
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if ("GET".equals(request.getMethod())) {
// ...
}
On JSF 1.2, you'd have used ResponseStatemanager#isPostback() for this.
On JSF 2.x, you'd have used FacesContext#isPostback() for this.
You could perform this in a getter of a (hidden) output component.
A completely different alternative is to install Tomahawk and use <t:saveState> to simulate the JSF 2.x view scope on a request scoped bean.

How to set struts ActionForm attributes using <html:link>?

I need to do the thing like this (setting ActionForm attribute):
<html:form action="Link.do?method=editNews">
<html:hidden property="idNews" value="${news.newsMessage.idNews}" />
<html:submit value="EDIT"/>
</html:form>
But in <html:link> or regular a-href tag. So I don't want this parameter to apear in my link as a request parameter. Is it possible?
P.S. idNews is the parameter in my ActionForm class and it has setter and getter.
No, it's not possible. A link performs a GET request, and the only way for a GET request to send information to the server is to use request parameters, which appear in the URL.
The only thing you can do is to have your link invoke a JavaSCript function which submits a hidden form using POST. But it's ugly.
Why do you fear by making the parameter visible in the URL? Are you aware that anybody can view the source of your HTML page and see the hidden field here?

JSF: bean scope; session vs request

I have a managed bean called UserSearchHandler, it has a doSearch method that populates UserSearchHandler.searchResults which are displayed in a table on the userSearch.xhtml page.
I have another managed bean called UserHandler, it has a showUser method and so on.
In the search results table, the user name is a link that, when clicked, is supposed to show user details on a userView.xhtml page. The table and link looks like this:
<p:dataTable var="user" value="#{userSearchHandler.searchResults" >
// ... and so on ... then
<h:commandLink value="#{user.firstName}" action="#{userHandler.showUser}">
<f:setPropertyActionListener target="#{userHandler.userIdToShow}" value="#{profile.id}"/>
</h:commandLink>
Everything works fine when the managed beans are set to session scope.
However, when I change the scope on the beans to request, the search works and the table gets populated, but when I click on the name link nothing happens. I put a break point on the userHandler.showUser method and it never gets hit when the userSearchHandler is set to "request" scope.
Can anyone help explain why this is, or what I'm doing wrong?
That's because the #{userSearchHandler.searchResults} is empty during the new request and therefore JSF is unable to locate the associated row where the commandlink is been invoked in order invoke the action (and to pass/set properties if any).
You need to ensure that the same #{userSearchHandler.searchResults} is precreated during bean's construction/initialization. If it's to be created based on a specific set of parameters, then you've to pass them along with the form as well.
That's exactly the reason why solutions like Tomahawk's <t:saveState /> and new JSF 2.0 view scope exist.
See also:
What are the main disadvantages of JSF 2.0?
I have a couple of ideas. If you're using a in your navigation you can try taking that out. Doing so would mean the browser will not make a new HTTP request when it renders the second window. It is the new HTTP request which clears the request scoped beans by. If that is not an option, you may be able to pass a parameter in your link such as a record id, which could allow you to pull data from your data source matching that id.

how to distinguish a jsf action or direct url link invoked the page

I have a situation, I have a session bean with list, this list I show in html data table. When the user hits the url from browser or normal href, I have to show all records. There is provision to search for the data also, where I have to show the filtered list. Now after a user has made the search, the list contains filtered records and after doing this he leaves the page to some other, and now if the user hits the url or uses the menu to come back to this page, since I have this list in session bean, I still have the filtered list.
Since there is no default action in JSF 1.1 or 2.0 preRenderView concept, its difficult to clear the list and get non filtered data(all results) again. Even tricks in getList() method fail to accomplish the task.
I have planned to use phase listener, as when a user reaches a page via href or url hit in browser, invoke application phase does not happen. I can toggle boolean variable in my session bean and in getList() I can perform some trick to check it was url,href hit or by command button.
Hope I have made myself clear. In short I have to identify in my bean whether the request came directly from href,browser or an action. If search action filter records for data table if not keep list cache and keep showing it as long as search is not made.
Just guide me whether I am doing things in right way or thinking too much or can it be done in much more efficient way.
Thanks in advance.
Well platform is jsf 1.1 in weblogic portal 10.3 .....
JSF 1.x actions use by default POST method. Direct links/bookmarks/etc are by nature GET method. Since there's no ResponseStateManager#isPostback() or FacesContext#isPostback() in JSF 1.1, you have to determine the request method yourself:
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
boolean postback = "POST".equalsIgnoreCase(request.getMethod());
Or check for a certain parameter in the request parameter map, but I can't tell from top of head which one you'd like to check. You've to determine it yourself.
boolean postback = facesContext.getExternalContext().getRequestParameterMap().containsKey(SOME_KEY);
If postback is true, then a JSF action is been invoked.

How to call an action method of a UICommand Component which was rendered conditionally?

action method is not called Please refer to this question - , One of my UICommand Component is rendered conditionally , it was said in the answer of the linked question - point 5 - that if the Component's or any of its parents rendered or disabled attributes are false - then the action method will not be called ? If thats the case- How do i achieve the same functionality? Is there a work around ? or a trick ? or any other approach ?
Thanks!
To the point, you'd like to retain the property responsible for the rendered condition in the subsequent request. There are several solutions for this problem:
Put bean in session scope. It's easy, but it hurts. It's bad for user experience since changes will be reflected in all tabs/windows the user has open in the same session.
Use <h:inputHidden> to transfer the property. In theory easy, but in practice it hurts as well. The value will namely get lost whenever a validation/conversion error has occurred in any of other inputs in the same form. This is an odditity in how JSF handles hidden input elements. A workaround is to use <h:inputHidden binding="#{bean.hidden}"> and do a hidden.getValue() and hidden.setValue() in bean.
If you're using <h:commandLink> instead of <h:commandButton>, then you can use <f:param> to transfer the property. It will be available as request parameter, you can check for it in bean's (post)constructor.
Use Tomahawk's <t:saveState>. The perfect solution as far. This will retain the value (or even a complete bean) in the subsequent request.
If you're already on JSF 2.0, the #ViewScoped would have solved this all. It behaves like the <t:saveState>.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
The trick is to have 'rendered' evaluate to true when it is time to run the action and then change the condition to false in the action method.
Let's say you have a link rendering based on a boolean in your bean called 'editing'. Then your action would look something like this:
public String myAction() {
// whatever you want your action to do
editing = false;
}
Edit: this assumes that the bean is either session scoped or the boolean get propagated between requests.
In my case, Javascript came for rescue, Which means, whatever was to be displayed conditionally , put them in a HTML Portion and don't display them display: none until the desired event occurs.
HTML Portion can have any JSF Tags(including CommandButtons) as you wish and would work (invoking the action methods and the stuff )perfectly okay.

Resources