Keep get parameters when submitting a form - jsf-2

I'm trying to do something simple in JSF but I can't get it working for some reason.
What I want is to post information with a form from a page reached with a GET parameter and keep this GET parameter whenever I submit the form.
<f:metadata>
<f:viewParam name="someId" value="#{someController.something}" converter="#{someConverter}" />
</f:metadata>
This is the way I choose to bind the GET parameter, this is working fine when I'm doing the GET request.
On the very same page I have a
<h:form>
<!-- (... various input ...) -->
<h:commandLink action="#{someController.create}" value="Create" />
</h:form>
When I submit it, even if data are right, I never get my "something" not to be null.
The use case is easy, I have a one to many relation and I want to access the "one" with the id as a GET parameter and list the "many" on the page and below the listing the form allows me to add a new element in the "many" list.
I'd like to make it work (of course) and be the cleaner possible,
Could someone tell me what's the best way to achieve this?
Thanks!

Either make the SomeController bean #ViewScoped so that the bean lives as long as you're interacting with the same view,
#ManagedBean
#ViewScoped
public class SomeController {
// ...
}
or use <f:param> in UICommand components to pass GET parameters through
<h:commandLink>
<f:param name="someId" value="#{param.someId}" />
</h:commandLink>

Related

Any way to bypass form validation on p:commandButton without using o:ignoreValidationFailed or immediate=true

I create page forms with a parameter that tells them where to return when done. The backing bean is #ReqeuestScoped and includes this:
<f:metadata>
<f:viewParam name="return" value="#{createGroup.paramReturn}" />
</f:metadata>
The form has fields with validators, so the cancel button has to skip validation. So, the cancel button looks like this:
<p:commandButton value="Cancel"
action="#{createGroup.doCancel}"
immediate="true"
/>
The purpose of the doCancel() method is to go into Flash scope and return the value set with setParamReturn method.
The problem is with the immediate="true" attribute is that the Flash storage that has the paramReturn variable in it is no longer available. If someone could tell me how to fix that this would be my preferred solution.
Of course without the immediate="true" attribute the action is never invoked because the form cannot pass validation. Another solution would be to cause validation to be ignored some other way.
I have looked at the OmniFaces <o:ignoreValidationFailed> tag and it seems to do what I want, but I don't want to import a whole library for just this tag. However, that is what I will do if there is no other simple way to fix this.

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.

Configuration of the beans when using <f:param> <f:viewParam>

I'm trying to pass a parameter between a JSF page to another, from a bean to another. I know it is a common question, infact I've tried several approaches before writing it down.
To do that I have put both the beans in session scope and added in the first bean the following:
<p:commandButton value="Submit" type="submit"
actionListener="#{sourceBean.save}" action="success">
<f:setPropertyActionListener
target="#{targetBean.foo}" value="#{sourceBean.foo}" />
</p:commandButton>
The problem is that I don't want these beans to be in session scope but in view scope.
So I tried to put in my first page:
<p:commandButton value="Submit" type="submit"
actionListener="#{sourceBean.save}" action="success">
<f:param name="foo" value="#{sourceBean.foo}"/>
</p:commandButton>
And in the second page:
<f:metadata>
<f:viewParam id="foo" name="foo" value="#{targetBean.foo}"
/>
</f:metadata>
The problem is that the passed String is null so, obviously, I get an error form the Converter.
I think I'm missing something in the configuration of my managed beans. Do I have to link target and source bean in someway?
At this moment I have this configuration:
<managed-bean>
<managed-bean-name>targetBean</managed-bean-name>
<managed-bean-class>guiBeans.TargetBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>sourceBean</managed-bean-name>
<managed-bean-class>guiBeans.SourceBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
Another question: In my app, the value foo.id, that I use during the conversion, is set autonatically by the database when I save the object so when I call:
actionListener="#{sourceBean.save}"
The converter gets the id and turns it into a String (and viceversa, if needed).
So, I wanted to know if in JSF is first called the actionListener or the function that sets the parameters .
Could be this the reason why I get a null String? Thanks a lot.
The <f:param> is evaluated during rendering of the form, not during submitting of the form. Your problem suggests that the #{sourceBean.foo} value is only been set during submitting the form and thus not available during rendering of the form.
You'd basically need to replace action="success" by action="#{bean.action}" with
public String action() {
return "success?foo=" + foo.getId();
}
Or, if you're using navigation cases
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/some.xhtml</to-view-id>
<redirect>
<view-param>
<name>foo</name>
<value>#{sourceBean.foo.id}</value>
</view-param>
</redirect>
</navigation-case>
Unrelated to the concrete problem, the <f:param> doesn't support the converter attribute at all. You'd have to access the desired property directly (which is id in the above example).

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.

JSF2 CommandButton Action request params

<h:commandButton value="Add Order" action="#{orderBasket.addItems(param['orderItemId'])}"/>
I can't get the above to work...when you click on the button the param seems to get set to null. Is there a way around this?
Is there another way of passing the URL params into the action method? I'm using Spring EL resolver which limits my ability to pass in the parameters into beans as I'm not using faces-config.
First, I think you could use JSF better, a lot of problems would be much simpler. It looks that you are using JSF as a request/response framework, like Struts. JSF is an object oriented component framework, you should use it this way to get the best of it.
I'll try to solve your problem, but I'm missing some information on what you are doing.
If you have a list of books that you can order, let's say they are displayed in a datatable (you could use ui:repeat instead) :
<h:dataTable value="#{bookController.books}" var="book">
<h:column>
<h:outputText value="#{book.title}" />
</h:column>
<h:column>
<h:commandButton value="Add Order" action="#{orderBasket.addItems(book)}" />
</h:column>
</h:dataTable>
In orderBasket backing bean, you simply take a Book (or whatever) as parameter. You don't need to handle the request/response cycle, certainly not in your views.
You can use f:ajax tag if you need to display that in your shopping cart immediately.
Let me know if you need more explanation (backing beans source or else).

Resources