With primefaces I made a multicheckbox with several divisions to choose. After clicking the submit Button the chosen divisions should be listed in a datatable with the associated items in a subtable. There could be 0 - n items which should be shown in the subtable.
division1 -> item1, item2
division2 -> item3, item4, item5
The first impression of the webpage looks fine. When I only choose one division and press submit the fitting items will be shown. But when I want to display other items they get overwritten. e.g. when I choose division2 it will display the items item1, item2 and item 5.
How can I make it so that the items will be loaded correctly every time?
I also changed the subtable to a nested datatable, but the behaviour was the same.
I've primefaces version 4.0
Below is my code:
division_list.xhtml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Gruppenverwaltung</title>
</h:head>
<h:body>
<f:view>
<h:form id="myForm">
<h2>
<h:outputText value="Division List" />
</h2>
<h:outputText value="Grid: " />
<p:selectOneRadio id="grid" value="#{divisionController.selectedDivisions}" layout="grid" columns="3"
converter="DivisionConverter">
<f:selectItems value="#{divisionController.divisions}" />
</p:selectOneRadio>
<p:commandButton value="Submit" update=":myForm" />
<p:dataTable id="dtDivisions" value="#{divisionController.selectedDivisions}" var="division">
<p:subTable id="stItems" var="item" value="#{division.items}">><f:facet name="header">
<h:outputText value="#{division.name}" />
</f:facet>
<p:column>
<h:inputText value="#{item.name}" />
</p:column>
<p:column>
<p:commandButton icon="ui-icon-disk" action="#{divisionController.doUpdateItem(item)}" />
<p:commandButton icon="ui-icon-trash" oncomplete="confirm.show()">
<f:setPropertyActionListener target="#{divisionController.selectedItem}" value="#{item}" />
</p:commandButton>
</p:column>
</p:subTable>
</p:dataTable>
</h:form>
<p:confirmDialog message="Gewählter Eintrag löschen?" widgetVar="confirm"> --><h:form
id="formDialog">
<p:commandButton value="Yes" action="#{divisionController.doDeleteItem}"
styleClass="ui-confirmdialog-yes" icon="ui-icon-check" oncomplete="confirmation.hide()" />
<p:commandButton value="No" type="button" onclick="confirm.hide()" styleClass="ui-confirmdialog-no"
icon="ui-icon-close" />
</h:form>
</p:confirmDialog>
</f:view>
</h:body>
</html>
DivisonController.java:
...
#ManagedBean
#ViewScoped
public class DivisionController implements Serializable {
...
private List<DivisionDto> divisions;
private List<DivisionDto> selectedDivisions;
...
#PostConstruct
public void init() throws MappingTOException {
....
if (divisions == null) {
divisions = club.getDivisions();
}
}
...
DivisionDto.java
...
public class DivisionDto {
....
private List<ItemDto> items;
private String name;
...
ItemDto.java
...
public class ItemDto {
...
private DivisionDto division;
private String name;
...
DivisionConverter.java
#FacesConverter(value = "DivisionConverter")
public class DivisionConverter implements Converter {
private static Map<String, DivisionDto> divisionCache = new HashMap<String, DivisionDto>();
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
DivisionDto val = divisionCache.get(value);
if (val == null) {
val = new DivisionDto();
val.setName(value);
}
return val;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value instanceof DivisionDto) {
DivisionDto division = (DivisionDto) value;
divisionCache.put(division.getName(), division);
return division.getName();
} else {
return "";
}
}
}
I would be really grateful for any help.
I solved the issue wie a datatable in a datatable and put a filter on the first datatable. Now it works as expected.
Related
This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 7 years ago.
I have a jsf form in my application which should display several input fields for creating / editing employees. There exists several departments which I want to display with a <h:selectOneMenu>. My other components are basically primefaces components.
If I select an existing employee from my datatable, the department is set correctly (in frontend and bean). I checked the converter and it's getAsString() method in debugging mode. Both seem to work fine.
But when I refresh the page with [F5] it changes the value in the <h:selectOneMenu> back to it's previous one but the bean's value is still fine. It seems that the binding between my session bean and the jsf component isn't working properly.
In addition, there's another problem when I want to save any employee. The validation shows me that the selectOneMenu value is invalid. This error occurs after the getAsObject() method successfully returns my department pojo. I didn't define any validators on this specific component but I use several input components who must not be empty. This error might occur because there's a problem with setting the value as I stated above.
DepartmentConverter.java
#ManagedBean(name="departmentConverter")
public class DepartmentConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
DepartmentDAOImpl deptUtils = new DepartmentDAOImpl();
try {
int code = Integer.parseInt(value);
return deptUtils.getDepartmentById(code);
} catch (NumberFormatException nfe) {
System.out.println("Couldn't transform department code from string to int");
nfe.printStackTrace();
}
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Department) value).getCode() + "";
}
}
SampleJSFBean.java
#ManagedBean(name = "sampleBean")
#SessionScoped
public class SampleJSFBean {
private Task employee;
private List<Task> employees;
private List<Department> departments;
private Department department;
public String showEditEmployeePanel() {
// shows panel
}
public String updateEmployee() {
// saves employee
}
// getter and setter
}
registration.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" template="/templates/BasicTemplate.xhtml">
<ui:define name="content">
<h:form id="formResult">
<p:panel>
<p:dataTable id="employee" var="task" value="#{sampleBean.employees}">
<p:column headerText="Code">
<h:outputText value="#{task.employee.code}" />
</p:column>
<p:column headerText="Name">
<h:outputText value="#{task.employee.lastname}" />
</p:column>
<p:column headerText="Department">
<h:outputText value="#{task.employee.department.name}" />
</p:column>
<p:column headerText="edit">
<p:commandButton id="btnMut" icon="ui-icon-pencil" title="edit employee" disabled="#{task.jobActive == true}" action="#{sampleBean.showEditEmployeePanel}"
update=":formEmployee" resetValues="true">
<f:setPropertyActionListener value="#{task}" target="#{sampleBean.task}" />
</p:commandButton>
</p:column>
</p:dataTable>
</p:panel>
</h:form>
<h:form id="formEmployee">
<p:growl autoUpdate="false" />
<p:panel id="panelEmployee">
<h:outputText value="Lastname" styleClass="labelForm" />
<p:inputText id="inputLastname" value="#{sampleBean.task.employee.lastname}" required="true" requiredMessage="Please enter lastname." />
<br />
<h:outputText value="Department" styleClass="labelForm" />
<h:selectOneMenu value="#{sampleBean.department}" converter="#{departmentConverter}">
<f:selectItems value="#{sampleBean.departments}" var="dept" itemLabel="#{dept.code} - #{dept.name}" />
</h:selectOneMenu>
<br />
<p:commandButton value="save" action="#{sampleBean.updateEmployee}" icon="ui-icon-disk" update=":formResult :formEmployee" />
</p:panel>
</h:form>
</ui:define>
Have you tried with primefaces component instead <h:selectOneMenu> use <p:selectOneMenu>.
I'm not sure it helps, but I always use primeFaces's selectOneMenu and always works.
Sample.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<f:event listener="#{sample.dosamplelist}" type="preRenderView" />
</h:head>
<h:body>
<h:form>
<h:panelGrid id="samplesetting" columns="6" cellpadding="5">
<f:facet name="header">Name Setting</f:facet>
<h:outputLabel for="samplename" value="Name:" />
<p:inputText value="#{sample.name}" id="samplename"
required="true" label="samplename" />
</h:panelGrid>
<p:panel id="sampleview" header="Sample List">
<p:dataTable var="spl" value="#{sample.samplelist}" rowKey="#{spl.name}"
selection="#{sample.selectedname}"
selectionMode="single">
<p:column headerText="Name">
<h:outputText value="#{spl.name}" />
</p:column>
<p:column>
<p:commandButton id="one" value="View Details" action="#{sample.setSelectedsample(spl)}" update="#form:samplesetting">
</p:commandButton>
</p:column>
</p:dataTable>
</p:panel>
</h:form>
Managed Bean
#SuppressWarnings("serial")
#ManagedBean(name = "sample")
#RequestScoped
public class Sample implements Serializable
{
private String name;
private List<Sample> samplelist;
private String selectedname;
//getters and setters
public void dosamplelist(ComponentSystemEvent event)
{
List<Sample> samplelist = new ArrayList<Sample>();
Sample configA = new Sample();
configA.setName("John");
samplelist.add(configA);
Sample configB = new Sample();
configB.setName("David");
samplelist.add(configB);
this.samplelist = samplelist;
}
public void setSelectedsample(Sample smpl)
{
this.name = smpl.name;
}
}
This is the sample of little big form, and the need is, when we select the table row from the bottom, it will be display to top input box for editing purpose.
But when I press the command button it do not work. why? and what is the reason please?
Possible Problem
One obvious problem is that at the class level, you've defined:
private List<Sample> samplelist;
Then you go ahead and hide the variable in doSampleList with
List<Sample> samplelist = new ArrayList<Sample>();
Combined with the fact that you have your bean marked as #RequestScoped, it will guarantee that the content of the samplelist will not be consistent during the JSF request processing.
To Solve:
Mark your bean as #ViewScoped instead and resolve the variable hiding problem as you see fit.
Further reading:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I am developing a project using JSF. In an opening popup window, i want to show some details about a product but can not get view scoped bean' s value on a datatable.
Can you help me?
Thanks.
Here is my UrunuDenetlemeSayfasi.xhtml code snippet:
<h:commandLink onclick="window.open('UruneGozAt.xhtml',
'Ürün İçeriği', config='width=700, height=400, top=100, left=100,
scrollbars=no, resizable=no');"
action="#{uruneGozAtBean.urunIdsineGoreUrunIcerigiGetir}" value="Ürün İçeriğine Göz At">
<f:param name="urunid" value="#{urun.urunID}" />
</h:commandLink>
Here is UrunuGozAt.xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:dataTable class="table table-striped"
value="#{uruneGozAtBean.urunIcerik}" var="urun">
<h:column>
<f:facet name="header">
<h:outputText value="barkod no" />
</f:facet>
<h:outputText value="#{urun.barkodNo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
Here is UruneGozAtBean.java
UrunDenetlemeSayfasiBean urunDenetle = new UrunDenetlemeSayfasiBean();
UrunDenetleService urunService = new UrunDenetleService();
private UrunIcerik urunIcerik = new UrunIcerik();
private Long urunIdParametre;
public UrunIcerik getUrunIcerik() {
return urunIcerik;
}
public void setUrunIcerik(UrunIcerik urunIcerik) {
this.urunIcerik = urunIcerik;
}
public Long getUrunIdParametre() {
return urunIdParametre;
}
public void setUrunIdParametre(Long urunIdParametre) {
this.urunIdParametre = urunIdParametre;
}
public void urunIdsineGoreUrunIcerigiGetir() {
setUrunIcerik(urunService.urunIdsineGoreUrunIcerigiGetir(urunIdEldeEt()));
}
public Long urunIdEldeEt(){
FacesContext fc = FacesContext.getCurrentInstance();
setUrunIdParametre(getUrunIdParametre(fc));
return getUrunIdParametre();
}
public Long getUrunIdParametre(FacesContext fc){
Map<String, String> parametre = fc.getExternalContext().getRequestParameterMap();
return Long.valueOf(parametre.get("urunid")).longValue();
}
EDIT:
This is now my current implementation, it returns null.
i am developing a project using JSF. In an opening popup window, i want to show some details about a product but can not get view scoped bean' s value on a datatable.
Can you help me?
Thanks.
Here is my UrunuDenetlemeSayfasi.xhtml code snippet:
<h:commandLink onclick="window.open('UruneGozAt.xhtml','Ürün İçeriği',
config='width=700, height=400, top=100, left=100, scrollbars=no, resizable=no');"
value="Ürün İçeriğine Göz At"> <f:param name="urunId" value="#{urun.urunID}" />
</h:commandLink>
Here is UruneGozAt.xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:metadata>
<f:viewParam name="urunId" value="#{uruneGozAtBean.urunId}"
required="false" />
<f:viewAction action="#{uruneGozAtBean.urunIdsineGoreUrunIcerigiGetir()}" />
</f:metadata>
<h:head>
<title>Ürün İçeriği</title>
<!-- add this always, even if it's empty -->
</h:head>
<h:body>
<h:dataTable class="table table-striped"
value="#{uruneGozAtBean.urunIcerik}" var="urun">
<h:column>
<f:facet name="header">
<h:outputText value="barkod no" />
</f:facet>
<h:outputText value="#{urun.barkodNo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
Here is UruneGozAtBean.java
#ManagedBean
#ViewScoped
public class UruneGozAtBean {
public UrunDenetlemeSayfasiBean urunDenetle = new UrunDenetlemeSayfasiBean();
public UrunDenetleService urunService = new UrunDenetleService();
private ArrayList<UrunIcerik> urunIcerik = new ArrayList<UrunIcerik>();
private Long urunId;
public Long getUrunId() {
return urunId;
}
public void setUrunId(Long urunId) {
this.urunId = urunId;
}
public ArrayList<UrunIcerik> getUrunIcerik() {
return urunIcerik;
}
public void setUrunIcerik(ArrayList<UrunIcerik> urunIcerik) {
this.urunIcerik = urunIcerik;
}
public void urunIdsineGoreUrunIcerigiGetir() {
setUrunIcerik(urunService.urunIdsineGoreUrunIcerigiGetir(urunIdEldeEt()));
System.out.print("aaa");
}
public Long urunIdEldeEt() {
FacesContext fc = FacesContext.getCurrentInstance();
setUrunId(getUrunId(fc));
return getUrunId();
}
public Long getUrunId(FacesContext fc) {
Map<String, String> parametre = fc.getExternalContext().getRequestParameterMap();
return Long.valueOf(parametre.get("urunId")).longValue();
}
}
#ViewScoped beans are alive per view. If you open a popup window from your current view, then you're opening a new view, so even if it uses the same managed bean to display the data, since they're different views, they use different instances of the same class.
In cases like this, you should pass a parameter through query string, then receive it in your view and process it to load the desired data. In this case, your code would be like this (note: make sure you send the parameter with name "urunId"):
UrunuGozAt.xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<!-- add this always, even if it's empty -->
<f:metadata>
<f:viewParam name="urunId" value="#{uruneGozAtBean.urunId}"
required="false" />
<f:viewAction action="#{uruneGozAtBean.loadData}" />
</f:metadata>
</h:head>
<h:body>
<h:dataTable class="table table-striped"
value="#{uruneGozAtBean.urunIcerik}" var="urun">
<h:column>
<f:facet name="header">
<h:outputText value="barkod no" />
</f:facet>
<h:outputText value="#{urun.barkodNo}" />
</h:column>
</h:dataTable>
</h:body>
</html>
UruneGozAtBean managed bean:
#ViewScoped
#ManagedBean
public class UruneGozAtBean {
//your current fields, getters and setters...
private Long urunId;
//getter and setter for this field...
public void loadData() {
if (urunId != null) {
//load the data for the table...
}
}
}
More info:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to choose the right bean scope?
DataTable expects a list to iterate through, but as far as I can see you return an UrunIcerik object.
I have a JSF 2 form like this:
<h:form>
<h:panelGrid columns="2">
<a4j:repeat value="#{dialog.departments}" var="depart">
<h:inputText value="#{depart.name}"/>
<h:selectOneRadio value="#{depart.hasSubdepartment}">
<f:ajax render="#form" execute="#form" immediate="true"/>
<f:selectItem itemValue="#{true}"/>
<f:selectItem itemValue="#{false}"/>
</h:selectOneRadio>
<a4j:repeat value="#{depart.subdepartments}" var="sub" rendered="#{depart.hasSubdepartment}">
<h:inputText value="#{sub.name}"/>
<h:outputText value=" " />
</a4j:repeat>
</a4j:repeat>
</h:panelGrid>
</h:form>
I have simply the form. As you could see, this form displays data structure of departments like a tree.
What I want to implements is that if user switch the radio button to true, the sub-departments will be displayed, if switch to false, the sub-departments will be hidden.
The problem is that:
If the execute value of the f:ajax tag is set to #form, the validation of the backing beans such as #NotNull and #Size will be called. But we don't want to call the validation now since we do not want to save the data now.
If the execute value of the f:ajax tag is set to #this, it seems that the after the ajax request, the value of the radio reverts. For example, if the radio value is false, and we click true, then after the ajax request, the value go back to false, and the sub-department part is not rendered. This will not happen if execute is set to #form.
Thanks very much if you have any idea or hint.
I don't have a Richfaces integrated testing environment, however I've achieved what you want in plain JSF (that's why it could be an ajax4jsf specific issue). Here you have a test case which works and follows SSCCE standards. Tested with Mojarra 2.1.26 & Tomcat 6:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<h:panelGrid columns="2">
<ui:repeat value="#{dialog.departments}" var="depart">
<h:inputText value="#{depart.name}" />
<h:selectOneRadio value="#{depart.hasSubdepartments}">
<f:ajax render="#form" immediate="true" />
<f:selectItem itemValue="#{true}" />
<f:selectItem itemValue="#{false}" />
</h:selectOneRadio>
<h:panelGroup id="subdepartmentPanel"
rendered="#{depart.hasSubdepartments}">
<ui:repeat value="#{depart.subdepartments}" var="sub">
<h:inputText value="#{sub.name}" />
</ui:repeat>
</h:panelGroup>
</ui:repeat>
</h:panelGrid>
</h:form>
</h:body>
</html>
#ManagedBean
#ViewScoped
public class Dialog {
public class Department {
private String name;
private List<Department> subdepartments = new ArrayList<Dialog.Department>();
private boolean hasSubdepartments;
public Department(String name) {
this.name = name;
}
public String getName() {
return name;
}
public List<Department> getSubdepartments() {
return subdepartments;
}
public boolean isHasSubdepartments() {
return hasSubdepartments;
}
public void setHasSubdepartments(boolean hasSubdepartments) {
this.hasSubdepartments = hasSubdepartments;
}
public void setName(String name) {
this.name = name;
}
public void setSubdepartments(List<Department> subdepartments) {
this.subdepartments = subdepartments;
}
}
private List<Department> departments = new ArrayList<Dialog.Department>();
public Dialog() {
// Create departments and subdepartments
departments.add(new Department("First Department"));
Department d = new Department("Second department");
d.getSubdepartments().add(new Department("Subdepartment"));
departments.add(d);
}
public List<Department> getDepartments() {
return departments;
}
}
I'm using an editable Primefaces p:datatable to show the data to the user. In this datatable, I have a p:column with a h:selectOneMenu, and another one with a p:selectBooleanCheckbox.
I want to check or uncheck and disable or enable the checkbox depending on the value selected in the h:selectOneMenu.
If I only had one h:selectOneMenu and one p:selectBooleanCheckbox, I'd use a p:ajax to attach a listener to the change event, and I'd manipulate the p:selectBooleanCheckbox in this method. But I have a pair of h:selectOneMenu and p:selectBooleanCheckbox per row and I don't know how to do this.
This is what I tried:
<h:form>
<p:dataTable var="appointment" value="#{prescController.appointmentsToday}" editable="true" id="tblAppointments">
<p:ajax event="rowEdit"
listener="#{prescController.onEdit}" update=":messages" />
<p:column sortBy="presc.drug" headerText="Drug">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{appointment.presc.drug.name}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{appointment.presc.drug}"
converter="#{drugConverter}" required="true">
<f:selectItem itemLabel="" noSelectionOption="true" />
<f:selectItems value="#{prescController.drugs}"
var="drug" itemLabel="#{drug.name}" />
<p:ajax update="autoAmount" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="presc.autoAmount" headerText="Auto amount">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="Y"
rendered="#{not empty appointment.presc.drug.rules and appointment.presc.autoAmount}" />
<h:outputText value="N"
rendered="#{empty appointment.presc.drug.rules or not appointment.presc.autoAmount}" />
</f:facet>
<f:facet name="input">
<p:selectBooleanCheckbox id="autoAmount"
value="#{not empty appointment.presc.drug.rules and appointment.presc.autoAmount}"
disabled="#{appointment.presc.drug.name eq 'somethingsomething'}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
The post Retrieving other component's client ID in JSF 2.0 describes how to retrieve ids of other components in a page. In my opinion, the #{p:component('sampleButton')} should find the next component having this ID in the component tree - this should be the same row.
Alternatively, you should be able to rerender the whole row via JSF 2 #{component.parent.clientId} functionality (measure out, how many "parent" steps you need, e.g. #{component.parent.parent.clientId}).
Hope it helps, else just add comments... :-)
I can't imagine why you are unsatisfied with simple update="checkboxId"but what you can try is updating component through widgetVar which you can generate during page render.
Tiny example:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Table Example</title>
</h:head>
<h:body>
<h:form prependId="false">
<p:dataTable var="data" value="#{tableBean.data}">
<p:column headerText="Command">
<p:commandButton value="Toggle" actionListener="#{tableBean.toggleSelection(data.id)}"
update="#widgetVar(tableCheckboxComponent_#{data.id})" />
</p:column>
<p:column headerText="Value">
<h:outputText value="#{data.value}" />
</p:column>
<p:column headerText="Selected">
<p:selectBooleanCheckbox widgetVar="tableCheckboxComponent_#{data.id}" value="#{data.selected}" />
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
Backing bean:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TableBean {
private Map<String, MyData> data;
public List<MyData> getData(){
return new ArrayList<MyData>(data.values());
}
public TableBean() {
data = new HashMap<String, MyData>();
for (int i = 0; i<22; i++) {
String id = "id" + Integer.toString(i);
data.put(id, new MyData( id , i));
}
}
public void toggleSelection(String id) {
MyData myData = data.get(id);
myData.setSelected(!myData.isSelected());
}
}
And Data object:
public class MyData {
private String id;
private boolean selected;
private int value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public MyData(String id, int value) {
this.id = id;
this.value = value;
this.selected = false;
}
}
I still don't know why my approach didn't work.
In the end, I added a listener to the p:ajax component to manipulate the SelectBooleanCheckbox in the managed bean
<p:ajax listener="#{prescBean.onDrugSelected}" update="autoAmount" />
public void onDrugSelected(AjaxBehaviorEvent event) {
Drug drug = (Drug) ((UIOutput) event
.getSource()).getValue();
boolean hasRules = drug.getRules().size() > 0;
SelectBooleanCheckbox cbAutoAmount = (SelectBooleanCheckbox) ComponentUtils
.findComponent(FacesContext.getCurrentInstance().getViewRoot(),
"autoAmount");
cbAutoAmount.setDisabled(!hasRules);
cbAutoAmount.setValue(hasRules);
}