<h:commandButton> does not invoke action - jsf-2

During some tests made using JSF 2 (mojarra on Glassfish 3.1.1) I've faced with strange behavior I can't explain.
This is my managed bean:
#ManagedBean
#RequestScoped
public class TestBean {
private int id;
public void hideButton() {
id = 0;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Here is my xhtml page
<h:form>
<h:inputHidden value="#{testBean.id}"/>
<h:outputText value="#{testBean.id}"/>
<h:commandButton value="set 1"
actionListener="#{testBean.setId(1)}">
</h:commandButton>
<h:commandButton value="hide button"
action="#{testBean.hideButton}" rendered="#{testBean.id > 0}">
</h:commandButton>
</h:form>
I expected, the button "hide button" is not visible on initial load of the page and this is really the fact. After a click on the button "set 1", the button "hide button" appeares and that is also to expect.
Really not understandable thing to me is the fact the subsequent click on the button "hide button" does not invoke the method testBean.hideButton and set the id to 0.
I've read the very useful answer from BalusC (thanks a lot really) here
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
and recognize, the problem is related to the attribute "rendered", if I remove it, the action is invoked.
But as far as I aware, the class member must be initialized during the UPDATE MODEL VALUES phase and the condition mentioned in the attribute rendered should be evaluated to true during INVOKE APPLICATION phase and the action should be invoked.
The example works if I change the scope of the bean to View/Session.
But it also works fine if I remove the render attribute from the "hide button"
Would somebody explain such behavior?
In other words, at what phase the expression of the rendered attribute is evaluated to make decision not to invoke the action?

The rendered attribute is also evaluated during apply request values phase, at the moment when JSF needs to identify which action needs to be invoked. If it evaluates false, then the action can't be identified and will thus also not be invoked.
The problem is caused by the too narrow managed bean scope. As your managed bean is request scoped, it get trashed by end of response and recreated (with all properties set to default) on any subsequent request. The model value on which the rendered attribute depends will only be updated during update model values phase, which is too late. You should be placing the managed bean in view scope instead.
Apart from changing the bean scope to view scope, another way is to check the request parameter map value instead in the rendered attribute.
<h:form id="form">
<h:inputHidden id="id" ... />
<h:commandButton ... rendered="#{param['form:id'] gt 0}" />
</h:form>
(by the way your usage of > instead of gt indicates that you're using the deprecated JSP view technology instead of Facelets, I would strongly recommend to migrate to Facelets)
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
How to choose the right bean scope?

I've found myself the reason of the problem.
The method UIComponentBase.processDecodes (at the Apply Request Values phase) calls isRendered, which returns false, because it is before the Update Model Values. Which skips the decode of the component.
There are some workarounds possible, all of them imho are not cool, but nevertheless it works
It is possible manually to set necessary value in managed bean in (post)constructor from request parameters.
Or to use

Related

h:commandLink inside h:dataTable not invoked [duplicate]

I am trying to execute an action through commandButton inside a dataTable, but the action is not invoked when the commandButton is placed inside the datatable as shown below
<h:form>
<h:dataTable value="#{bean.list}" var="item">
<h:column>
<h:commandButton value="submit" action="#{bean.submit}" />
</h:column>
</h:dataTable>
</h:form>
When I move the commandButton out of dataTable, the action is successfully executed. What is the problem when commandButton is inside datatable? The commandLink has the same problem.
This problem can happen when the list behind #{bean.list} is not exactly the same during the HTTP request of processing the form submit as it was during the request of displaying the form. JSF will namely re-iterate over the list to locate the button pressed and invoke its action.
If the bean is request scoped and the list is not repopulated during bean's (post)construction, or the list's population depends on a request scoped variable which was lost during the form submit, then JSF will retrieve an empty or a completely different list while processing the form submit and thus won't be able to locate the button pressed and won't invoke any action.
The best fix is to put the bean in the view scope and ensuring that you're loading the data model the proper way.
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private List<Item> list;
#EJB
private ItemService service;
#PostConstruct
public void init() {
list = service.list();
}
// ...
}
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4
Benefits and pitfalls of #ViewScoped

JSF 2 + Primefaces: Need to update bean property on menu click before rendering dialog

I have a p:menuitem that needs to (1) update a backing bean property when clicked, and then (2) show a p:dialog.
This is the set up I have:
<p:menuitem value="Show Dialog"
oncomplete="dialog_widget.show();"
update=":dialog"
actionListener="#{bean.setCurrentAction}">
</p:menuitem>
<p:dialog widgetVar="dialog_widget" id="dialog" dynamic="true">
<h:form>
<p:inputText value="#{bean.record.text} />
// the proper rendering of this dialog form depends on bean.currentAction
// being set during JSF Phase 4 Update Model Values
</p:dialog>
And the backing bean:
public R getRecord() {
if (currentAction == null) {
return null;
}
return currentAction == NEW ? newRecord : selectedRecord;
}
The problem is that actionListeners and actions are only executed during Phase 5 and I need the bean.currentAction to be set before that so the dialog can be properly updated and rendered.
** A little background on what I'm trying to achieve: the dialog form is used to Create new records as well as Update exsiting records (Add and Edit Dialog). So the "currentAction" on the bean indicates which action the user is doing. Depending on which action, the form needs to use different model objects ("newRecord" or "selectedRecord") to pull and save the form data to.
Although not a very elegant solution you can use PrimeFaces' RequestContext's update method to set update target and use the execute method to show your dialog in your actionListener after setting the needed property.
If you requirement is to call the backing bean method before the dialog opens then you can go for a ajax function (i don't know whether you are allowed to use ajax in your application). for p:menuItem there is a function called onclick, where you can call a a4j:ajax function through which you can call a backing bean method and update the model before dialog opens.
By default action is called during "Invoke Application" phase. You can add immediate="true" attribute in p:menuitem tag. This will call action in "Apply Request Values" phase.

JSF: setting a property in a wizard form with multiple submit actions

I have this scenario: in the first tab of a primefaces wizard component, I have some fields and a button. The button saves some data, does some business logic and, with the results, sets some properties of the form bean (which is in ViewScope) that are not related to a specific field of the form. I have checked that in the invoke application phase, the values are set properly.
In the second tab I have another button that has to do some business logic using the values set by the first one but, doing some debug, I noticed that the values, even if not related to any field of the form, are overwritten I think during the update model phase invoked when I click the second button.
How can I avoid this? Is there a way to obtain the correct behaviour?
I looked around but I couldn't find any example of a wizard form with multiple submissions. Thanks for help!
<p:wizard widgetVar="wiz" render="true" id="wizard" showNavBar="false">
<p:tab id="step0" title="Step0" step="0">
<!-- Some other fields-->
<p:commandButton value="Save and do some business logic"
action="#{formBean.save}"
oncomplete="wiz.loadStep (wiz.cfg.steps [1], false)">
</p:commandButton>
</p:tab>
<p:tab id="step1" title="Step1" step="1">
<!-- Some other fields-->
<p:commandButton value="Second button: use the previous informations"
action="#{formBean.doSomething}"
oncomplete="wiz.loadStep (wiz.cfg.steps [2], false)">
</p:commandButton>
</p:tab>
</p:wizard>
Edit:
To show an example I can say that my bean contains a business logic object. During the first submission, this object is being saved so the database (Mysql and Hibernate), assigns to it a progressive id.
During the second submission, when I try to read this id, the value is zero so, obviously, I get an error.
Something like:
public class FormBean{
private BLObject object;
// Constructor Getters and setters
// Method executed during the first submission
public void save(ActionEvent actionEvent) {
//Save the object and set his id
PersistanceClass.getInstance().save(object);
}
// Method executed during the second submission
public void doSomethingWhitTheId(ActionEvent actionEvent) {
//Access the id... id=0 returned
int id = object.getId();
}
}
The problem was that, navigating from one page to another, Primefaces wizard, uses a String to identify the tab. Returning the value of this String, which is not null nor void, makes the view bean go out of scope. It is ok when you have a simple form but, if you wanna set some properties not related to a form element during the flow, they get overwritten during the tab changes.
I solved the problem adding to the form an hidden parameter linked to the property I wanted to preserve.
<h:inputHidden value="formBean.idToPreserve" id="inputHidden" />

Primefaces ManyCheckbox inside ui:repeat calls setter method only for last loop

I have a <p:selectManyCheckbox> inside <ui:repeat>, getting it's items from a List of a certain Object Class (provided by <ui:repeat>-variable) and is supposed to save the chosen items into another List of the same Object Class. But it calls the setter method #{cartBean.setSelectedExtras} only for the last entry (last iteration of <ui:repeat>).
<ui:repeat var="item" value="#{category.items}">
<p:selectManyCheckbox id="extraCheckbox" value="#{cartBean.selectedExtras}" layout="pageDirection" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{item.items5}" var="extra" itemLabel="#{extra.name}"/>
</p:selectManyCheckbox>
</ui:repeat>
Update:
I changed the above construct just the way BalusC proposed.
Declaration in backing bean is now:
private List<List<Item>> selectedExtras = new ArrayList<List<Item>>();
When I check checkboxes that were created by the first loops of <ui:repeat> and click the <p:commandButton> inside the same <h:form> the setter method of selectedExtras is not called. When I check the checkboxes created in the last loop of <ui:repeat> and click the <p:commandButton> I get an Exception:
javax.el.PropertyNotFoundException: /lightbox-item.xhtml #57,165 value="#{cartBean.selectedExtras[iteration.index]}": null
This construct works fine for me.
As mentioned in among others the showcase page, the omnifaces.SelectItemsConverter uses by default the toString() representation of the complex object as converted item value. So if you didn't override the toString() method (so that it still defaults to com.example.SomeClass#hashcode which changes on every instantiation) and the #{item} managed bean is request scoped, then the list would basically be changing on every HTTP request. This would cause a "Validation Error: Value is not valid" error.
If you add
<p:messages autoUpdate="true" />
or
<p:growl autoUpdate="true" />
so that you get all (missing) validation/conversion messages in the UI, then you should have noticed it.
In order to utilize the omnifaces.SelectItemsConverter at its best, you should override the toString() method accordingly so that it returns a fixed and unique representation of the complex object. E.g.
#Override
public String toString() {
return "Extra[id=" + id + "]";
}
Alternatively, you could put the #{item} managed bean in a broader scope, such as the view scope.
Update as to your update, you're binding the selected values of all checkboxgroups to one and same bean property #{cartBean.selectedExtras}. This way every iteration overrides the property with the values from the current iteration round as long as until you end up with the values of the last iteration. If you've placed a debug breakpoint on the setter, you'd have noticed that.
This is not right. They should each point to a different bean property. Technically, you should have a #{item.selectedExtras} as property. But I think that this makes no sense in your current design. Better would be to make the #{cartBean.selectedExtras} an List<Item[]> or Item[][]. This way you can get them to set based on the iteration index as follows:
<ui:repeat var="item" value="#{category.items}" varStatus="iteration">
<p:selectManyCheckbox id="extraCheckbox" value="#{cartBean.selectedExtras[iteration.index]}" layout="pageDirection" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{item.items5}" var="extra" itemLabel="#{extra.name}"/>
</p:selectManyCheckbox>
</ui:repeat>
In case of List<Item[]> you only need to make sure that you preinitialize selectedExtras with nulls as many times as there are #{category.items} in bean's (post)constructor.
for (Item item : category.getItems()) {
selectedExtras.add(null);
}
In case of Item[][], you can suffice with
selectedExtras = new Item[category.getItems().size()];

JSF2: commandLink action method not always called

I have two very similar usecases, one works, and another one does not. I have checked the basic things mentioned in other answers (JSF2.1 on JBoss 7.1.1 with PrimeFaces 3.3).
First the sample which works:
<h:form id="processInstanceList">
<p:dataTable id="instances" var="processInstance" value="#{processInstanceList}">
...
<p:column>
<h:commandLink value="#{msg.deleteButtonLabel}"
action="#{runtimeService.deleteProcessInstance(processInstance.id, 'Cancelled by user')}">
</h:commandLink>
with the action methods signature:
void deleteProcessInstance(String processInstanceId, String deleteReason);
and now the sample which does not work:
<h:form id="taskGrouplist">
<p:dataTable id="groupTasks" value="#{groupTaskList}" var="v_task">
...
<p:column>
<h:commandLink value="Übernehmen" action="#{taskList.claimTask(v_task)}"/>
with the action methods signature:
#Named
#RequestScoped
public class TaskList {
public String claimTask(Task task);
on the second sample the task passed to the action method is always NULL. If I just pass an attribute of the task to the method, e.g. with #{taskList.claimTask(v_task.id)} (Task has a getId() method returning a String) and changing the action methods signature to public String claimTask(String id) ... everything I pass in is NULL.
Why doesn't this happen in the first sample? There I pass in two Strings and it works fine...
What is the scope of your RuntimeService bean?
Try to change your TaskList bean scope to ViewScoped or SessionScoped, here is why:
#RequestScoped: A request scoped bean has a lifetime of exactly one HTTP request/response.
So once your dataTable with commandLinks gets rendered (the HTTP request/response is over) you lose all the references for v_task parameters in your action="#{taskList.claimTask(v_task)}" calls.
#ViewScoped: A view scoped bean lives as long as you're interacting with the same JSF view.
Even after the rendering is over, because of the #ViewScope you still have your references on v_task object.

Resources