ActionListener is called multiple times (Bug?) - Mojarra 2.1.3 - jsf

I have the following button:
<h:commandButton
disabled="#{mybean.searching}"
binding="#{mybean.searchButton}"
actionListener="#{mybean.searchForLicenses}"
value="Search" />
When I debug I see that the actionListener is called twice first, then three times, next click four times and so on.
It seems like on every reload the actionListener is registered one more time.
I'm using Mojarra 2.1.3 (also tried 2.0.6) and Tomcat 7 with IceFaces.
The binding is done that way:
private javax.faces.component.UICommand searchButton;
public void setSearchButton(UICommand searchButton) {
this.searchButton = searchButton;
}
public UICommand getSearchButton() {
return searchButton;
}

That can happen if you've bound the component to a session or application scoped bean instead of a request scoped bean. This is simply a bad design. The very same component would be reused among multiple requests/views. You need to put the bean in the request scope, or to get rid of the component binding altogether.
Note that binding the component directly to a bean is often a sign of poor design somewhere in the code. What is it, the functional requirement and/or problem for which you thought that this is the solution? If you elaborate on that, we may be able to propose the right approach.
Also note that using an action listener alone is also a design smell. I'd expect "searchForLicenses" to be a normal action method. See also Differences between action and actionListener.

The similar issue takes place when component is using binding and validator or valueChangListener and backing bean is of View, Session or Application scope. Then corresponding listeners are called many times but not once during request (+1 time with every new request).
One possible solution is to override jsf class AttachedObjectListHolder which is used for storing component listeners. Current implementation simply add new listener to component even though the same listener is already there. So the proposed fix is to check that listener does not exist before adding it.
Details of the fix you can see here

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 {
......
}

Doing something whenever user exits particular page

I have a internet shop application. I wanted to improve "removing from the cart" feature. I don't want to ask an user if he wants to "really remove" the position from the cart, instead I'd like to allow him cancel the operation.
Currently when user clicks "X" button at the product in the cart, row of table changes to "removed, click to cancel". In the back there is a list of CartPosition objects every with flag removed. Removed product is still on list, but the flag is set to true. It makes product still visible in proper position on the list, but on the view side I can render it another way. When user clicks another "X", previous one is premamently removed from the list and new one is marked as removed.
Shopping cart is session scoped CDI bean. It means, when I mark some position removed and go somewhere else, then go back to the cart, I'll still have one row marked as removed. I just don't want this.
I thought about changing the bean to JSF one, then create another view scoped which could keep record marked as removed and check if it's empty, if so I could remove the one from list. I have no idea if it's going to work. I'll try this approach, but I'd rather keep my beans managed by CDI.
Is there a way to handle this without implementing my above idea?
EDIT: #BalusC, your assumptions are wrong. You should rather suppose, that I don't exactly know how can I mix CDI and JSF. I actually use JSF 2.2, what means that javax.faces.view.ViewScoped annotation is available for me. Anyway I still don't understand the idea. I understood, that I have to rely on some ViewScoped bean. It's clear, but how it has to be composed. Can you explain your idea? I tried few things, but it looked it didn't work correctly. For example my #PreDestroy method of ViewScoped bean was never called and it's constructed lazily only when I try to use it.
Do the actual remove job in #PreDestroy annotated method of the session or view scoped bean.
#PreDestroy
public void destroy() {
// Do the actual remove job here.
}
Given that your question implies that you don't have CDI based javax.faces.view.ViewScoped available, which is new since JSF 2.2, this in turn suggests that you're still on JSF 2.0/2.1 and thus only have JSF based javax.faces.bean.ViewScoped at hands, then it should be noted that its #PreDestroy is broken in several circumstances. You'd then best do the #PreDestroy in the CDI based #SessionScoped bean. Alternatively, you could use OmniFaces #ViewScoped which has fixed and improved the #PreDestroy of a #ViewScoped bean in several ways. It even gets invoked on window unload.
As far as I understood your problem is the session. One way to solve the problem is to set the list of removed products in a request attribute and remove it from the session bean so that on the next request they will disappear.
Hope that helps

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?

Refreshing a component bind to request-scoped bean

Does anyone have a solution for such a problem:
In my app I'm using a complex, programmatically build dashboard based on the primefaces dashboard. To overcome problems with nonunique id's of the panels building the dashboard, I'm binding this component to a request-scoped bean. I'd also like to rebuild the dashboard based on some changable parameters after clicking a commandButton.
The problem is, that the getter for the dashboard is fired in the Apply Request Values phase, way before the actionListener of the commandButton is fired (in the Invoke Application phase). So, although the dashboard is rebuild eventually, it's not beeing refreshed in the rendered response.
On the other hand, if I try to set immediate attribute of the button to true, the actionListener is fired in the Apply Request Values phase, but still after the getter. Than the lifecycle goes directly to the Render Response phase, and the outcome is the same.
Anyone?
Thank you for the answer. Let me add a bit detail to my problem.
I store a model of a sports tournament as a property of a session scoped bean. It goes like this: the bean has a property "tournament". This class has a list of groups, each with it's table of matches. The idea was to use three different programmatically built components as renderers of this tournament model.
The dashboard would be used for drag-and-drop edition of contestant placement in groups. For viewing match tables and editing their matches I use a tab panel, with panel grid for every table. Finally, I use a panel grid to show a tournament tree. Every of those three components render some part of the model for the user to edit.
Since the model (and therefore those rendering components) are dynamically build depanding on chosable parameters like number of groups for example, i had a problem with id uniqnes when binding them to a session-scoped bean. So I bound them to a request scoped bean. With every request changing the model (mostly ajax) I wanted to rerender those components depending on the parameters set by the user (also stored in the session scoped bean).
The problem is, that when I rebuild the model in the invoke application phase (in a action listener fired by the "rebuild-my-model" button), the components bound to a request-scoped bean have already been "get-ed" from the bean (or so it seems), and they do not refresh on the page.
I would be very gratefull for a clue to what i'm doing wrong, and perhaps a suggestion, if the approach mentioned above is completelly stupid :)
The problem is, that the getter for the dashboard is fired in the Apply Request Values phase, way before the actionListener of the commandButton is fired
I'm not sure why exactly that forms a problem for you. Perhaps you're incorrectly doing business logic in the getter method instead of in the action listener method? Or perhaps you're manually creating the component instead of referencing the JSF-created one and thus always overridding the one in the JSF view?
A proper JSF getter method basically look like this:
public UIComponent getDashboard() {
return dashboard;
}
It should not contain any other line of code. The same applies to the setter method by the way. Any actions wherein you need to manipulate the component's children needs to be done in an action(listener) method, not in a getter/setter method.

JSF CDI Bean initialization on every page access

I'm currently learning about JSF 2.0 and i dont know how to initialize something in my CDI bean everytime a jsf page is accessed ?
For example, let's say in my case, i have one CDI bean that is used in one JSF page. Somewhere inside the bean, i would like to query and initialize something, or check authorization everytime the page is accessed (not everytime the action method is called).
I could put it into the bean's constructor, but that doesnt guarantee that the constructor would be called for every calls of the jsf page ? Or should i call using the #{myBean.initialize()} on the JSF page ?
Regards,
Albert Kam
If you declare the managed bean #RequestScoped, then it will be created for every HTTP request (yes, that's "everytime a JSF page is accessed" as you say in enduser's terms). You can just do the initialization job in the bean's constructor or #PostConstruct method. This has nothing to do with CDI.
check authorization everytime the page is accessed (not everytime the action method is called).
For that, a javax.servlet.Filter or very maybe a javax.faces.event.PhaseListener is a much better solution.
You could have a look at https://cwiki.apache.org/confluence/display/EXTCDI/JSF+Usage
If I am not mistaken, the constructor is called every time the page loads - as soon as you apply your bean to the jsf page, that object is constructed. Hence, must have a constructor without any parameters

Resources