My requirement on this one was to have some linked logic between select checkboxes on table rows and a ‘select all’ checkbox in the column header. Checking ‘select all’ should check all the row boxes. Then, unchecking one or more of the row boxes should uncheck ‘select all’ as the rows are no longer all checked.
Initially I had decided to get a whole test form working without Ajax, then apply the desired Ajax to all of it consistently. I had previously hit event timing issues due to mixing Ajax and HTTP submits on the same form. This gave rise to strange behaviour such as old queued events seeming to fire from nowhere, and events containing null arguments in method expressions. The basic wisdom on this is don’t mix Ajax and traditional HTTP submits on the same form – bad things will happen! I therefore decided to get the code logic working first with plain submits, by adding “onclick=’submit();’” to the checkboxes to force submits temporarily. The idea behind this was to avoid getting a mix of problems due to Ajax and problems due to other coding bugs, by eliminating the other coding bugs first.
The approach when doing this kind of thing is typically to set the components to immediate=”true” and call FacesContext.getCurrentInstance().renderResponse(); at the end of the value change listener to force an immediate rendering.
The problem I hit however, was that although I was correctly setting bean values for other checkboxes from the listener, the values were not being read again prior to renderResponse(),so the new values were not being displayed on the page. This is in fact standard behaviour. The way to update the values being rendered is to call setValue() on the actual UIInput Component as well as writing the backing bean. To do this you need to get at the component instance, and the best way to achieve this is to use the binding attribute in the JSF page. For example, the following code fragments could be used in the JSF page and the managed bean:-
JSF Page
<h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
valueChangeListener=”#{mainBean.selectedListenerB}”
binding=”#{mainBean.selectBoxBBinding}”
id=”chkSelectB” immediate=”true” onclick=”submit();”>
</h:selectBooleanCheckbox>
Managed Bean
private UIInput selectBoxBBinding;
public UIInput getSelectBoxBBinding() {
return selectBoxBBinding;
}
public void setSelectBoxBBinding(UIInput selectBoxBBinding) {
this.selectBoxBBinding = selectBoxBBinding;
}
Value Change Listener
public void selectedListenerA(ValueChangeEvent event) {
boolean newValue = (Boolean)event.getNewValue();
setSelectedA(newValue);
//SelectedB is set to the same value as selectedA
setSelectedB(newValue);
selectBoxBBinding.setValue(newValue);
FacesContext.getCurrentInstance().renderResponse();
}
This causes the new value to be displayed in the updated checkbox. Binding to a component allows access to a number of other properties and methods as well, so gives a lot of flexibility. However, in most normal cases straightforward value binding is enough.
Using Ajax to achieve the same result
Ironically, if I had used Ajax on this issue, I would not have hit the problem. When Ajax is used, setting the new values in the managed bean is enough to allow them to be displayed directly on screen. The following JSF fragment shows how to use Ajax in check box SelectA in order to directly update check box SelectB without using a form submit. execute=@this causes the server side processing for SelectA to be performed (@this means the current component and is the default). render=”chkSelectB” causes the rendering to be peformed for SelectB, which displays the new value. Both execute and render take a space delimited list of client Ids, or special keywords such as @this, @form, @all, @non etc. The Ids can be prefixed with “:” to force Id scanning from the root where there are naming container issues etc. I am not covering any of this here.
<h:outputText value=”Select Box A”/>
<h:selectBooleanCheckbox value=”#{mainBean.selectedA}”
valueChangeListener=”#{mainBean.selectedListenerA}”
id=”chkSelectA”>
<f:ajax execute=”@this” render=”chkSelectB”/>
</h:selectBooleanCheckbox>
<br/><br/>
<h:outputText value=”Select Box B”/>
<h:selectBooleanCheckbox value=”#{mainBean.selectedB}”
valueChangeListener=”#{mainBean.selectedListenerB}”
binding=”#{mainBean.selectBoxBBinding}”
id=”chkSelectB”>
</h:selectBooleanCheckbox>