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

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).

Related

Keep get parameters when submitting a form

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>

commandLink actionListener methods on bean passed via ui:param

I'm using JSF 2 with PrimeFaces, and my facelet has commandLinks (or commandButtons) that calls methods on a bean passed in via ui:param.
My facelet xhtml expects dialogBean to be passed as a ui:param
<h:panelGroup>
<p:commandButton
value="#{msgs.ok}"
actionListener="#{dialogBean.okClicked}"
process="#{dialogId}"
update="#{dialogId}, #{externalIdsToUpdateOnOk}"
styleClass="dialogBottomBtn"
/>
<p:commandButton
value="#{msgs.cancel}"
actionListener="#{dialogBean.close}"
process="#this"
update="#{dialogId}"
styleClass="dialogBottomBtn"
/>
</h:panelGroup>
The facelet is included like this:
<ui:include src="/faces/common/dialogButtons.xhtml">
<ui:param name="dialogId" value="textBlockQuestionDialog" />
<ui:param name="dialogBean" value="#{formEditor.textBlockQuestionDialog}" />
<ui:param name="externalIdsToUpdateOnOk" value=":form:tree, :form:properties, :form:preview" />
</ui:include>
It fails with this error:
javax.el.PropertyNotFoundException: Target Unreachable,
identifier 'dialogBean' resolved to null
I've tried replacing #{dialogBean.close} with #{dialogBean['close']}, #{dialogBean[action]} with action defined as param, nothing helped.
dialogBean does get resolved when used with h:outputText and similar outputs. Also, this example works when I replace actionListener with action.
Any ideas anyone?
I think I found the answer.
Double-check that your dialogBean object's actionListener methods (okClicked etc.) take an ActionEvent parameter.
It seems like this parameter is required for beans passed by ui:param, but not others.
I suspect what's going on is something like this:
check dialogBean parameter for method okClicked(ActionEvent)
if not found, look for bean named dialogBean with method okClicked(ActionEvent)
if not found, look for bean named dialogBean with method okClicked()
where the no-argument method is only used when the bean name directly matches, not indirectly matches via ui:param reference.

Passing view parameter through backing bean

I have an inputtext in a page page1.xhtml and I want to pass the value the user will enter into a second page page2.xhmtl as a view parameter using a get method. I use an h:button and put as outcome value from the backing bean but it when I navigate to the second page I the parameter is not passed. What's wrong? Is the value not passed to the backing bean before pressing the button and therefore value cannot be read? Is there another way to do it?
page1.xhtml
h:inputText id="q" value="#{QBean.q}"></h:inputText>
<h:button value="Done" outcome="page2?q=#{indexBean.q}">
page2.xhtml
<f:metadata>
<f:viewParam name="q" value="#{QBean.q}"/>
</f:metadata>
QBean
private String q;
//setter
//getter
Your sole functional requirement seems to be that you want a GET form instead of a POST form. In that case, use normal HTML elements, not JSF components.
<form action="page2.xhtml">
<input name="q" />
<input type="submit" value="Done" />
</form>
You could use the POST-REDIRECT-GET approach and take commandButton instead: <h:commandButton value="Done" action="page2?faces-redirect=true&includeViewParams=true"/>

Understanding navigation in JSF

Trying to build a simple JSF application. One i don't get is, what mechanism is to use to trigger page reload. I have tried following
<h:selectOneMenu
id="ChallengesListBox"
onchange="submit()"
valueChangeListener="#{bean.projectselected}">
<f:selectItems value="#{bean.projectnames}"/>
</h:selectOneMenu>
<h:commandButton value="submit" action="#{bean.submit}" />
with
public String submit() {
this.description.setRendered(true);
return null;
}
But this has no effect. The bean method
public String submit()
remains untouched, as I can see in debug mode.
This is not related to navigation. There are many causes why a bean action method is not invoked. You can find them all in this answer: commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I suspest that you've either simply no <h:form>, or that you have multiple buttons in the form (the first one would then be invoked on submit()), or that the button is by itself not rendered during processing of the form submit.
Unrelated to the concrete problem, this JSF 1.x style approach is very clumsy. As you're apparently already on JSF 2.x, I suggest the following much simpler approach:
<h:selectOneMenu value="#{bean.projectname}">
<f:selectItems value="#{bean.projectnames}" />
<f:ajax render="somepanel" />
</h:selectOneMenu>
<h:panelGroup id="somepanel">
<h:outputText value="#{bean.description}" rendered="#{not empty bean.projectname}" />
</h:panelGroup>
(this will render the #{bean.description} value whenever the #{bean.projectname} is not null/empty according to the selection of the drop down list)
And make sure that you remove all binding attributes to the backing bean. Also make sure that the bean is #ViewScoped whenever you have input/button components inside the <h:panelGroup id="somepanel">.

JSF creates new instance of the same class for each el expression in facelets

I have a login page in a web application project:
<h:form>
<h:messages />
<h:inputText label="Username" value="#{login.username}" required="true" />
<h:inputSecret label="Password" value="#{login.pass}" required="true" />
<h:commandButton value="Accedi" action="#{login.check()}" />
</h:form>
When I submit the form, jsf creates three instances of Login class (I've noticed this behavior using debugger). In this way I can't use the username and password in Login.check() method: they are both null.
Besides I've tested another more complex project I've created some time ago and it works fine: only one instance is created. I don't understand where I'm wrong.
Take a look at the managed bean configuration of the login bean (either annotations of the class or in faces-config.xml), specifically its scope. A scope of "none" would have exactly the effect you're observing. The appropriate scope would probably be "request".

Resources