Setting Managed Bean attribute's value from JSF page and using it in bean's methods - jsf

I have a ViewScoped Managed Bean. In my .xhtml page I want to set bean's attribute's value and use it in methods in the same bean.
I managed to set the value from jsf page, but when i want to use it in some method the value of an attribute is not the value i have set before.
Description (xhtml):
In this form there is a command link which sets the value of an attribute. And it is working fine. Also, as command link is clicked, second form is being showed.
<h:form>
<h:commandLink value="Set" >
<f:setPropertyActionListener target="#{bean.attribute}" value="true" />
<f:ajax execute="#this" />
</h:commandLink>
</h:form>
This form executes method that uses attribute's value set before, but the value is not true, its false.
<h:form>
<h:commandButton id="submit" value="Execute" action="#{bean.execute}" />
</h:form>
Bean:
public void execute(){
if(isAttribute())
---do something---
}
The question is: Why execute() is not reading attribute's value right?
When I use one form, it's working fine. But I need them to be in separated forms.

The scope of your bean is incorrect. ViewScoped means that the minute the view is changed, the bean is discarded and re-created for the next view. So, in your case, the original data you had for the first view is lost.
I'm going to refer you to BalusC's blog:
http://balusc.blogspot.co.uk/2010/06/benefits-and-pitfalls-of-viewscoped.html
which states:
A #ViewScoped bean will live as long as you're submitting the form to the same view again and again. In other words, as long as when the action method(s) returns null or even void, the bean will be there in the next request. Once you navigate to a different view, then the bean will be trashed

I can't determine of you stay on the same page with both requests. If you do, viewScope should work even in two different forms. If you are navigating from 1 view to another, another viewScope will be created and you will loose the current one.
You could set the value in the sessionScope with java or by annotating the backingNean. But then everything in your backingBean becomes sessionScoped and that might not be needed.
You could also use a spring-like flow scope.
Example to do it with java:
public void callThisAfterFirstClick() {
Faces.setSessionAttribute(attribute, true)
}
public void callThisAfterSecondClick() {
Faces.getSessionAttribute(attribute);
}

Related

How to use component binding in JSF right ? (request-scoped component in session scoped bean)

Mojara 2.1.21
I've updated my question based on comments. I have two situation where a component is bound to server session bean. (Additional links with information: Binding attribute causes duplicate component ID found in the view and https://stackoverflow.com/a/12512672/2692917)
Version 1:
single.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 2:
template.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}"
view1.xhtml:
<ui:composition template="template.xhtml" />
view2.xhtml:
<ui:composition template="template.xhtml" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 1 is ok. (At least I've not encounter any errors so far). But in version 2 the duplicate id error is occured if I navigate from one page to another. Why does it happen ?
Is it safe to use (request-scoped) component (in version 1) with session scoped binding ?
Are there another use cases to consider ?
Edit:
Functional requirement 1:
I want to use Primefaces datatable in a view. I need some info from this datatable. (Such as selected row or row index). So binding the datatable helps me to retrieve this info.
Functional requirement 2:
Components binding in composite components. They will be bound to session scoped bean. (And used mainly on one page, but what if I used it on another page ?
Requirements 3
The situation as in "Version 2". Template with primefaces menu and session scoped binding. For this I've used the EL-Binding.
In JSF 2.x, unless you want to manipulate components programmatically (which is at its own also rather fishy), there is no sensible real world use case to bind components to a backing bean. For sure not if they are further not been used in the backing bean itself, or if it are solely their attributes which are been flattened out.
As to the functional requirement of getting the current row of the data table, there are much better ways listed here, How can I pass selected row to commandLink inside dataTable?, for example if your environment supports EL 2.2:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:commandLink value="Foo" action="#{bean.foo(item)}" />
The two last requirements are totally unclear. At least, if you're doing something like:
<x:someComponent binding="#{bean.someComponent}" />
with in bean
someComponent.setSomeAttribute(someAttribute);
someComponent.setOtherAttribute(otherAttribute);
then you should instead be doing
<x:someComponent someAttribute="#{bean.someAttribute}" otherAttribute="#{bean.otherAttribute}" />
Or, if you intend to be able to use the component somewhere else in the view like so
<h:inputText ... required="#{not empty param[bean.save.clientId]}" />
...
<h:commandButton binding="#{bean.save}" ... />
and the instance is further nowhere been used in the bean, then just get rid of the unnecessary property altogether:
<h:inputText ... required="#{not empty param[save.clientId]}" />
...
<h:commandButton binding="#{save}" ... />
If there is really, really no way for some unclear reason, then split all request scoped properties of the session scoped bean out into a separate request scoped bean which you in turn bind to form actions. The session scoped one can just be injected as a #ManagedProperty of the request scoped one.
See also:
Binding attribute causes duplicate component ID found in the view
How does the 'binding' attribute work in JSF? When and how should it be used?
We ran into a similar problem and I just want to share our solution:
Problem:
In a view there was a (extended largely customized) datatable.
<x:dataTable binding="#{bean.someSomeDataTable}" />
After navigating to another page and back we wanted the datatable to have the exact same state. Previously we solved that by binding the datatable to to backing bean. This worked fine with JSPs. With Facelets we could not do that (Duplicate ID errors). So we used the binding, but only saved/restored the state of the datatable component.
public HtmlDataTable getSomeDataTable()
{
HtmlDataTable htmlDataTable = new HtmlDataTable();
if (tableState != null)
htmlDataTable.restoreState(FacesContext.getCurrentInstance(), tableState);
return htmlDataTable;
}
public void setSomeDataTable(HtmlDataTable table)
{
tableState = table.saveState(FacesContext.getCurrentInstance());
}

#ViewScoped, f:setPropertyActionListener only works once

I have 2 managedBeans: the first one (RequestScoped) sends a parameter to the second one (ViewScoped) through a h:commandLink. Both managedBeans are in the same page, but I use them in different tabs from a rich:TabPanel:
#ManagedBean
#RequestScoped
public class TheRequestScopedManagedBean {
private String number
...
#ManagedBean
#ViewScoped
public class TheViewScopedManagedBean {
private String number;
...
And here's the view, wich uses a rich:dataTable:
(The action method is only for showing the second tab from a rich:tabPanel).
// ... another dataTable's columns
<rich:column>
<f:facet name="header">Number</f:facet>
<b>
<a4j:commandLink value="#{theRequestScopedManagedBean.number}"
render="someRichPanel" action="#{anotherBean.showSecondTab}" immediate="true">
<f:setPropertyActionListener target="#{theViewScopedManagedBean.number}" value="#{theRequestScopedManagedBean.number}" />
</a4j:commandLink>
</b>
</rich:column>
The problem here is that theViewScopedBean shows the value only the first time, and when I try to pass it again, it shows its default value (null).
I've seen several questions on this website. But I really don't know what to do in this case.
action="#{anotherBean.showSecondTab}" is going to result in a navigation case firing. This will in turn result in the views and request scoped beans being destroyed and recreated (as is the expected behaviour for a view scoped bean).
If you're using EL2.2, you could easily just pass the value directly into a method in the view scoped bean. Let's assume your viewscoped bean has a method takeValue, you can pass the parameter directly into the method as in:
<a4j:commandLink value="#{theRequestScopedManagedBean.number}" render="someRichPanel" action="#{theViewScopedBean.takeValue(theRequestScopedManagedBean.number)}" immediate="true"/>
There are still cleaner ways to transmit data between pages.
Communication in JSF2.0

JSF pass Object to another page

I'm trying to pass an object to another site. So i have my Gallery.xhtml where I set an object as current and redirect to another page:
<h:form>
<a4j:commandButton value="Edit Skin"
action="#{helloBean.setCurrentSkin(skin)}"
onclick="window.location.href = 'resources/html/Editor.xhtml';" />
</h:form>
But when the getter on the second page is called, the current object is null again.
Is the bean generated for each page? How could I achieve this?
My Problem was that I declared my bean as #ViewScoped, but the proper Tag is #SessionScoped. This makes sure that the Bean holds its values for the whole session and not only one view.

f:setPropertyActionListener sets null value instead of intended value

My view is:
<h:commandLink value="BookFlight" action="#{bookSeatController.doLoginOrCC}">
<f:setPropertyActionListener target="#{bookSeatController.flightNumber}"
value="#{flightInfoController.flight.number}" />
</h:commandLink>
My setter is:
public void setFlightNumber(String flightNumber) {
this.flightNumber = flightNumber;
}
When I use the debugger I get a flightNumber of null in the setter. However, if I change the view to the following:
<h:commandLink value="BookFlight" action="#{bookSeatController.doLoginOrCC}">
<f:setPropertyActionListener target="#{bookSeatController.flightNumber}"
value="122334" />
</h:commandLink>
The flightNumber property is set to 122334. How is this caused and how can I solve it to set the intended value instead of null?
If the #{flightInfoController.flight.number} is request scoped, then it has to preserve exactly the same flight in during the request of processing the form submit as it was during the request of displaying the form. This has to happen in the bean's (post)constructor.
If that is not an option, because it depends on some request based variables, then your best bet is to put the bean in the view scope instead (I however still assume that your bean is properly designed that it doesn't do any business/preloading job in getters).
If putting the bean in the view scope is in turn not an option, then you'd need to pass it as a fullworthy request parameter instead. You can do that by <f:param>.
<h:commandLink value="BookFlight" action="#{bookSeatController.doLoginOrCC}">
<f:param name="flightNumber" value="#{flightInfoController.flight.number}" />
</h:commandLink>
You can let JSF set it by #ManagedProperty in the BookSeatController or by <f:viewParam> in the current view.
See also:
How can I pass selected row to commandLink inside dataTable?
ViewParam vs #ManagedProperty(value = "#{param.id}")
If it's working when assigning "122334" but when assigning flightInfoController.flight.number it's "null" and since you are not receiving any exception, then it means probably your flightInfoController is not properly initialized (regarding it's field flight and hence number in the flight).
Just make sure the bean is properly initialized (or update your OP with the bean code).

h:inputText value not set in bean

The <h:inputText> value is not been set in a request scoped bean. If the value is preserved from DB, it works fine.
view:
<h:inputText id="receipient" size="90" styleClass="text" readonly="#{!bean.enable}" value="#{bean.recipient}" />
bean:
public class Bean {
private String recipient;
Bean(){
recipient = //load from db
}
//set
//get
}
What is the problem and how can I solve this?
Ensure that readonly="#{!bean.enable}" evaluates the same as it was in initial view. If it evaluates true during apply request values phase of the form submit, then the component's value won't be processed (because it is marked as read only).
An easy test is to put the bean in session scope. If that fixes it, then you know the culprit. If you're using JSF 2.0, just put bean in view scope by using #ViewScoped instead of #RequestScoped. If you're still on JSF 1.x, use Tomahawk's <t:saveState> component to let the bean act like the JSF 2.0 view scoped one.
<t:saveState value="#{bean}" />

Resources