viewscoped bean doesn't save session parameter - jsf-2

I have a page with datatable with product information from which at a product selection action I redirect to product info page passing a parameter:
configurableNavigationHandler.performNavigation("productInfo?faces-redirect=true&prId=" + selectedCpl.getP().getPrId());
In my viewscoped bean in my init method I get the request parameter and fill the objects needed:
#ManagedBean
#ViewScoped
public class ProductInfo implements Serializable {
private Product p;
private Integer prId;
#PostConstruct
private void init() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
if (request.getParameter("prId") != null) {
prId = Integer.parseInt(request.getParameter("prId"));
p = pf.find(prId);
On my productInfo.xhtml I have a product info view and a dialog to edit the product info but when I press submit my the request parameter is null:
<p:commandButton styleClass="button-edit" value="Submit" actionListener="#{productInfo.saveProduct()}" update="prodInfo" oncomplete="dlg.hide();"/>
I'm using jsf 2.0 with primefaces elements.
Can anyone help me? Thank you.

That's not a session parameter. That's a request parameter. That it's null is because you are not sending it along with the submit request. Send it by <f:param>.
<p:commandButton ...>
<f:param name="prId" value="#{productInfo.prId}" />
</p:commandButton>
Unrelated to the concrete problem, there are several other potential problems. First, the view scoped bean should not be recreated when you submit the form. Perhaps you're using tag handlers in the view. Second, you should absolutely avoid hauling the raw javax.servlet API from under the JSF covers as much as possible. Use ExternalContext#getRequestParameterMap() instead. Third, the <f:viewParam> is much cleaner than that postconstruct. Fourth, redirecting by a navigation handler smells like a design problem in the view, e.g. why not use just a GET link?
The in-depth explanations on all of those issues are available in Communication in JSF 2.0.

Related

evaluate jsf bean property based on URL

Is there a way to display a specific JSF page based on the request URL?
Let's say I have a JSF page "details.xhtml". The managed bean "detailsBean" has a list of objects where each object has its own ID. Now if a user requests the page "../details.xhtml?id=1", the list should be queried for an object with ID 1 and the resulting details page of this object should be displayed.
I already wrote a converter implementation class which can convert from object to ID and vice versa, but I don't know how to use it properly. Do I have to work through the JAX-RS specification for this to work or is there a more simple solution?
In JSF you can do this by using a so-called view parameter. You declare these in the metadata section of your Facelet:
<f:metadata>
<f:viewParam name="id" value="#{yourBean.yourObject}" label="id"
converter="yourObjectConverter"
/>
</f:metadata>
This will grab the URL parameter id from the request URL. E.g. if you request the page this appears on with localhost:8080/mypage.jsf?id=1, then 1 will be handed to the yourObjectConverter and whatever this converter returns will be set in yourBean.yourObject.
Your backing bean will thus get the converted object. No need to pollute your backing bean over and over again with the same query code.
#ManagedBean
public class YourBean {
private SomeObject someObject;
public void setYourObject(SomeObject someObject) {
this.someObject = someObject;
}
}
If your backing bean is view scoped, you may want to use the OmniFaces variant of viewParam instead, since otherwise it will needlessly convert after each postback (if your converter does a DB query, you definitely don't want this).
Working full examples:
http://code.google.com/p/javaee6-crud-example/source/browse/WebContent/user_edit.xhtml
http://code.google.com/p/javaee6-crud-example/source/browse/src/backing/UserEdit.java
Further reading:
Communication in JSF 2.0 - Processing GET request parameters
Stateless vs Stateful JSF view parameters
You can achieve this with plain JSF with the following steps
Capture the ID in the request to determine what object is being queried for in your DetailsBean from the request parameter. There are many ways to achieve this, one of which is adding the following annotation to your managed bean (this is currently only permitted for a #RequestScoped bean, see why here).
#ManagedProperty(value="#{param.id}")
int requiredObjectId;
The annotation above will capture the id parameter from the request and assign it to the requiredObjectId variable.
Using the captured Id, setup your object in your bean in a #PostConstruct method
#PostConstruct
public void queryForObject(){
//use the requiredObjectId variable to query and setup the object in the backing bean
}
The object retrieved should be assigned as an instance variable of your managed bean
In your view, you could then reference the queried object that has been setup in the backing bean
<h:panelGrid columns="2">
<h:outputText value="Title"/>
<h:outputText value="#{detailsBean.selectedObject.title}"/>
</h:panelGrid>
If your bean is in a scope broader than the request scope, you'll need a combination of constructs to cleanly pull that request parameter before view rendering.
Capture the request parameter within the JSF view itself using
<f:metadata>
<f:viewParam name="id" value="#{detailsBean.requiredObjectId}" required="true" requiredMessage="You must provide an Object Id"/>
</f:metadata>
**OR**
Due to the nature of JSF Lifecycle processing, doing the above alone may not make the value available for your use in time for object setup. You could use the following instead.
<f:metadata>
<f:event type="preRenderView" listener="#{detailsBean.setObjectId}" />
</f:metadata>
What we've done here is specify a method (that captures the id) in the backing bean that must be executed before the view is rendered, ensuring that the id parameter is available as at the time you need it. Proceed with step 3, only if you're using <f:event/> above.
In the backing bean, you now define the setObjectId method
public void setObjectId(){
Map<String,String> requestParams = FacesContext.getExternalContext().getRequestParameterMap();
requiredObjectId = Integer.parseInt(requestParams.get("id"));
}
Note that the above option is generally a work around/hack and not a clean solution as such

<h:commandButton> does not invoke action

During some tests made using JSF 2 (mojarra on Glassfish 3.1.1) I've faced with strange behavior I can't explain.
This is my managed bean:
#ManagedBean
#RequestScoped
public class TestBean {
private int id;
public void hideButton() {
id = 0;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Here is my xhtml page
<h:form>
<h:inputHidden value="#{testBean.id}"/>
<h:outputText value="#{testBean.id}"/>
<h:commandButton value="set 1"
actionListener="#{testBean.setId(1)}">
</h:commandButton>
<h:commandButton value="hide button"
action="#{testBean.hideButton}" rendered="#{testBean.id > 0}">
</h:commandButton>
</h:form>
I expected, the button "hide button" is not visible on initial load of the page and this is really the fact. After a click on the button "set 1", the button "hide button" appeares and that is also to expect.
Really not understandable thing to me is the fact the subsequent click on the button "hide button" does not invoke the method testBean.hideButton and set the id to 0.
I've read the very useful answer from BalusC (thanks a lot really) here
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
and recognize, the problem is related to the attribute "rendered", if I remove it, the action is invoked.
But as far as I aware, the class member must be initialized during the UPDATE MODEL VALUES phase and the condition mentioned in the attribute rendered should be evaluated to true during INVOKE APPLICATION phase and the action should be invoked.
The example works if I change the scope of the bean to View/Session.
But it also works fine if I remove the render attribute from the "hide button"
Would somebody explain such behavior?
In other words, at what phase the expression of the rendered attribute is evaluated to make decision not to invoke the action?
The rendered attribute is also evaluated during apply request values phase, at the moment when JSF needs to identify which action needs to be invoked. If it evaluates false, then the action can't be identified and will thus also not be invoked.
The problem is caused by the too narrow managed bean scope. As your managed bean is request scoped, it get trashed by end of response and recreated (with all properties set to default) on any subsequent request. The model value on which the rendered attribute depends will only be updated during update model values phase, which is too late. You should be placing the managed bean in view scope instead.
Apart from changing the bean scope to view scope, another way is to check the request parameter map value instead in the rendered attribute.
<h:form id="form">
<h:inputHidden id="id" ... />
<h:commandButton ... rendered="#{param['form:id'] gt 0}" />
</h:form>
(by the way your usage of > instead of gt indicates that you're using the deprecated JSP view technology instead of Facelets, I would strongly recommend to migrate to Facelets)
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
How to choose the right bean scope?
I've found myself the reason of the problem.
The method UIComponentBase.processDecodes (at the Apply Request Values phase) calls isRendered, which returns false, because it is before the Update Model Values. Which skips the decode of the component.
There are some workarounds possible, all of them imho are not cool, but nevertheless it works
It is possible manually to set necessary value in managed bean in (post)constructor from request parameters.
Or to use

Replacing a managed bean instance from the backing bean

Doing a CRUD, I have a RequestScoped Ticket bean.
I have an XHTML page that until now I have been using to create the new Tickets; the ticket fields are populated directly (#{ticket.description} and so on)
Now I have a search form that lists the tickets, and with each ticket a link with the ticket id as a parameter. I want the backing bean to retrieve the ticket bean from EJB/JPA (already done) and put it into the request. I see 3 ways to do so:
Copy the data from the bean retrieved from JPA into the bean provided by injection. Ugly / prone to omissions.
Use ExternalContex#getRequestMap and put the bean there myself. Does not look very proper. Am I right?
Include my ticket bean into another bean class so I can do myNewBean.setTicket(ticketFromJpa);. Seems the best of the options, yet I do not like having to prefix all my EL in the page just for this.
There is out there any cleaner, more proper way of doing what I want?
Thanks in advance.
UPDATE:
To reword what I want, with a little more information. I have a commandLink in page P1, that calls action A in backing bean B1. B1 does its logic and redirects to page P2.
I wanted to set a (request scoped) bean B2 in action A, and that B2 would be available to draw P2.
From experiments, I have found that after leaving action A the framework creates a new B2 request scoped bean, so it looks like that the request scope is shorter than I expected.
The flash scope propesed by Damian looks like it works more like I want, but forces me to redesign the page around #{flash} and that (when I want to use it to create a new bean) I must also add the bean to the flash in an action method (currently it justs goes to the page and the managed bean is available)
I expected a Request scoped bean to be maintained since
To view the ticket in another page, you could do one of the following:
1) use h:link with a f:param containing the ID of the ticket
<h:link value="#{ticket.description}" outcome="/viewTicket" >
<f:param name="id" value="#{ticket.id}" /
</h:link>
Then in the viewTicket.xhtml (or whatever you called the page) you read the ID parameter, and get the ticket from JPA.
This is how the managed would basically look like:
#ManagedBean
#ViewScoped
public class ViewTicketMBean implements Serializable {
private String ticketId;
private Ticket ticket;
#PostConstruct
public void init() {
ticketId = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id");
// read ticket from JPA by ID
}
}
2) instead of h:link, if you don't want to expose ticket ID, you can use a commandLink, which before navigating to viewTicket.xhtml, gets the ticket from JPA and puts it in flash scope. Then, in viewTicket you get the ticket from the flash scope. This is how the action method of the commandLink couldl look like
Ticket ticket = null;
// get ticket from JPA
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("ticket", ticket);
return "/viewTicket";

What scope to use in JSF 2.0 for Wizard pattern?

I have a multi-page form, aka a Wizard pattern, where Page 1 corresponds to Step 1 of the wizard form, Page 2 corresponds to Step 2, etc. Each page other than the last has a Next button on it that takes you to the next page in the form. The final page has a submit button that submits all the data for all pages in the wizard.
What scope should I use to maintain the state of the data entered on each form? e.g. should I use a View Scoped bean that holds all the data entered on all pages? Will that work since I'll be navigating to different pages (Which I believe are considered to be different "views"; and if they're different views, I believe the View Scoped data will be lost when you navigate to the next page in the wizard)
I believe the View Scoped data will be lost when you navigate to the next page in the wizard)
That's correct. The view scope lives as long as you're interacting with the same view and get trashed whenever a new view get created. You're looking for the "conversation scope". This isn't available by any of the JSF managed bean scopes. This is however available by CDI #ConversationScoped. So if your environment happen to support CDI, you could make use of it:
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#ConversationScoped
public class Wizard implements Serializable {
#Inject
private Conversation conversation;
#PostConstruct
public void init() {
conversation.begin();
}
public void submitFirstStep() {
// ...
}
// ...
public String submitLastStep() {
// ...
conversation.end();
return "someOtherPage?faces-redirect=true";
}
// ...
}
The conversation is managed by the automatically inserted cid request parameter.
If you'd like to stick to the JSF view scope, then your best bet is to create a single page wherein you render the multiple steps conditionally:
<h:panelGroup rendered="#{wizard.step == 1}">
<ui:include src="/WEB-INF/wizard/step1.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 2}">
<ui:include src="/WEB-INF/wizard/step2.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 3}">
<ui:include src="/WEB-INF/wizard/step3.xhtml" />
</h:panelGroup>
Or, you could use a 3rd party component library like PrimeFaces which has a <p:wizard> component for exactly this purpose.
From my pov, good choice here is session scoped beans. When needed, user will be able to interrupt the wizard, visit other pages, doc, manuals, whatever, and get back to the same wizard step. Of course it can be done via view-scoped beans (see BalusC answer). Personally I prefer view-scoped beans when ajax is heavily involved. In that case I'd recommend to combine these two scopes.
You can find an example using the conversation scope for creating a wizard at this site:
JEE6 – CDI and Conversation Scope

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