How to pass information between beans in JSF 2? - jsf

I have a scenario and dont have a clear idea for this to work yet.
Here's the example scenario :
I have a myView.xhtml file that can be displayed as a window popup or a primefaces dialog popup from 2 other container xhtml, let's say container1.xhtml and container2.xhtml (the myView.xhtml is included with something like this ? <ui:include src="myView.xhtml" />)
And, we also have the view-scoped beans, let's call them myViewBean, container1Bean and container2Bean
container1Bean has the property of transactionDate, and container2Bean has a property of transDate
myViewBean's #PostConstruct method will query the database based on a parameter of type date.
On container1.xhtml, if a user clicks on a button that will popup the myView.xhtml, container1Bean should be able to provide it's transactionDate to the myViewBean, and myViewBean will be able to query based on it in the #PostConstruct method.
On container2.xhtml, if a user clicks on a button that will popup the myView.xhtml, container2Bean should be able to provide it's transDate to the myViewBean, and myViewBean will be able to query based on it in the #PostConstruct method.
I was thinking about using #Inject Container1Bean and #Inject Container2Bean in the MyViewBean, so that inside MyViewBean, i can get the transactionDate of container1Bean or transDate of container2Bean. To decide which container bean is active is to check which one is not null.
But what if the container beans grows, there could be other container beans that make use of the MyViewBean, and the #Inject ContainerXXBean will grow in numbers inside the MyViewBean. There must be other solutions for this.
Please share ideas on how to accomplish this .. Thank you ! :-)
Thank you !

If you want to access only the contents of the other beans you can do that programmatic.
Get the current instance of the FacesContext inside from one bean. And using that context you can grab the instance of other beans.
See this illustration. As per the title of your question, you want to some information between beans. You can accomplish this by calling the other bean's public methods, which may be specifically created for this purpose. (setters-getters).

If container1Bean, myViewBean and container2Bean share some properties, why not putting them in a new bean ? (let's call it sharedBean, but I'm sure you'll find a better name adapted to your case). You could then inject sharedBean using #ManagedProperty in every dependent bean. Let's just try not to have circular references.
I'll also suggest to review your architecture. Are you sure you need all thoses beans, partitionned exactly like this? This sounds like something which will be difficult to maintain.

Related

How to update bean in database on a RequestScoped view?

First of all, sorry for my english. I have a RequestScoped ManagedBean in order to send parameters to other views, without getting the The scope of the object referenced by expression is shorter than the referring managed beans error. I also have in the same RequestScoped view a p:dataTable showing these beans objects, with an update button for each row, that retrieves this bean to another form in the same view to be update with new values.
The problem is, when I hit the submit button to record the new values, another record is created, instead of the older one being updated. Of course, because the bean is killed when the submit button is pressed (RequestScoped), creating a new bean and another record in the DB. How can I fix it in this scope?
I've seen some alternatives using #PostConstruct here, however I'm not entirely sure it would solve my specific problem.
EDIT:
After researching a bit more into this topic, I came to another doubt: I am using the same Bean in both views (in my case, ProjectBean), should I create a new Bean with RequestScoped annotation (something like ProjectIdBean), set the older one to ViewScoped (so I can reproduce updates naturally on my Database), and let this new Bean handle the requests for other views?
Submit button:
<p:commandButton value="Gravar" action="#{projetoBean.gravar}"
process="#form" update="#form :formTabelaProjetos:tabelaProjetos" />
'Gravar' method:
public void gravar() {
System.out.println("Gravando projeto " + this.projeto.getNome());
ProjetoDAO dao = new ProjetoDAO();
if (this.projeto.getId() == null) {
dao.adiciona(this.projeto);
projetosAtivos = this.getProjetosAtivos();
} else {
dao.atualiza(this.projeto);
}
this.projeto = new Projeto();
}
You can use request scoped backing bean for updating entities. The problem is, that the request life cycle ends when your page is rendered. So anything you loaded will get discarded. The submit creates another request, that will try to reload resources, but it is a different request than the previous one and for example request parameters often do not contain what the programmer expects. But this is what you found out already. There are two ways how to deal with the problem:
1) use simple getters and setters to set "String, Integer" and similar variables in your request scoped bean, that you use to reconstruct and modify the entity you want to update. It is not convenient for the programmer but request scoped beans save resources of your server.
2) change the scope of your backing bean. Session scope is not ideal, because it can stay in memory for a really long time. And you might realize you need to clean it up manually. Much better is ViewScoped bean as it allows you to work with the entities you loaded over several steps. It gets wiped out when the user leaves the page.
#javax.faces.bean.ViewScoped
#javax.faces.bean.ManagedBean
public class SomethingBean {
......
}

saving data in between pages

I have been reading about JSF navigation between pages in an application and I am still a little bit confused. I have a small web application with a series of pages with continue and previous buttons on each page. To save the valid data entered on the view, I am trying to figure out ways to make the valid form data stick when the user goes back and forward. Initially, I had the page views in session scope but I understood that its bad practice. The data that I am capturing can be a managed bean with composite objects within the bean that corresponds to the data that is captured in the pages. But, I read that managed bean in session is not a good idea either. After reading through so many posts, I feel that I should know the solution but its still not very clear as to how to save the validated data into JSF so that it displays when the user navigates back and forth? Appreciate your help.
Seems to me you're trying to accomplish some kind of wizard-like navigation. For this use-case I would suggest the use of a #ConversationScoped backend Bean.
This scope is not provided by the JSF- but by the CDI-framework which just work perfectly together.
To get this to work you essentially have to follow these steps:
Create a CDI Bean like:
#Named
#ConversationScoped
public class MyBean implements Serializable {
#Inject
private Conversation conversation;
...
}
#Named is the CDI alternative to JSFs #ManagedBean.
Your class should implement the Serializable interface to be able to passivate its state.
CDI #Inject the Conversation-object to use in your code.
Start the conversation anywhere inside your code via:
conversation.start();
Do your magic: process input, change data, navigate, persist to db,...
End the conversation (in your case at the last page, maybe after a click on a 'Finish'-Button)
conversation.end();
A quick google search came up with this pretty tutorial implementing a questionaire site which could be useful to you. Have a look at this.
Hope this helps. Have fun!
Are you not persisting the data to a database? If so, you can use a request-scoped managed bean, that way when you navigate back to the original page the updated records will be re-retrieved from the database and your changes will be displayed.

Can JSF be configured to not invoke Entity setter unless the field actually changed?

When a JSF form field is wired into an entity bean field (which is mapped to a DB field), each setter in the entity bean is called regardless of whether the user changed the form field value in the front end, i.e. the setters on unchanged fields are invoked the same as those that have changed but their new value is the same as the old value.
My question is simple: Is there a way to configure JSF to only call the setters mapped to the fields that have changed in the front end? The reason for this is that I have a requirement by which I have to detect deltas on every persist and log them, more about which can be read in this question.
Maybe I didn't understand you clearly, but why are you mapping directly your entity beans to a JSF view ?! IMHO it would be better if you add managed beans between your JSF pages and the entities in order to better separate your business logic from data access.
Any way, I think the easiest solution to impelement for that case is by making use of Value Change Events which are invoked "normally" after the Process Validations phase (unless you make use of the immediate attribute).
The good news about Value Change Events (regarding your example) is they are invoked ONLY after you force form submit using JavaScript or Command components AND the new value is different from the old value.
So, as an example on how to use value change listeners, you can add valueChangeListner attribute to each of your JSF tags like following:
<h:inputText id="input" value="#{someBean.someValue}"
valueChangeListener="#{someBean.valueChanged} />
Then, implement your valueChanged() method to look something like:
public void valueChanged(ValueChangeEvent event) {
// You can use event.getOldValue() and event.getNewValue() to get the old or the new value
}
Using the above implementation, may help you to separate your logging code (it will be included in the listeners) from your managed properties setters.
NB: Value Change Listeners may also be implemetend otherwise using the f:valueChangeListener Tag, but this is not the best choice for your example (you can find some examples in the section below, just in case)
See also:
Valuechangelistener Doubt in JSF
JSF 2 valueChangeListener example
When to use valueChangeListener or f:ajax listener?

adf managed bean retrieving a value from input text

I'm trying to retrieve a value from an input text in my jsf page, but when I change its value it doesn't change in the managed bean.
here's the input text:
<af:inputText label="Código:" id="codigo" value="#{tipoBaixaBean.codigo}"/>
and my managed bean is annotated like this:
#ManagedBean
#RequestScoped
public class TipoBaixaBean {
private long codigo;
I have the getters and setters, but the value of the property "codigo" never changes,
What would be the problem??
Thank you
Change your Bean scope to 'pageFlowScope' or 'viewScope' in adfc-config.xml . That should do.
You don't say when you are trying to get the value...on page submit or when you tab out of the field. If you want the value when you tab out (lose focus) then set the autoSubmit property on the input text field to true.
I would also suggest using a print statement in set method to make sure it's being called. The scope issue only arises if you are trying to retain the value between page requests.
Not sure how can you bind an inputText to a long object in backing bean.
Ideally it should be something like
private RichInputText codigo;
you can get the value of codigo using the getter.
getCodigo.inputValue();
I don't think scope will cause any problem. It works for the least life scope i.e. backing bean scope.
It really depends on the exact moment in which you are getting/setting the value, but if you need to do it automatically every time a change occurs, then you'll need to implement the Value Change Listener. Check this out: Value Change Listener example

Is there a limitation in JSF 2.0 to access attributes of the complex Managed Bean?

The scenario is the following:
A managed bean uses as attributes another managed bean, like customerBean.current.customerAgreement. When I display the data on a pge the expression #{customerBean.current.customerAgreement.agreementTitle} is filled and shows the expected output.
However in an inputText the value is only changed on the screen, not in the value I get back in the managedBean. Is there a limitation on how deep such a structure can be constructed?
No, there is basically no limitation in how deep you can nest beans.
Your problem is caused by something else. Perhaps you are not preserving the same parent beans in the request of the form submit as it was during the request of the form display. Hard to tell without further detail about your code. All what I can suggest is to try making CustomerBean a view scoped bean.

Resources