Reputation: 2501
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>
Upvotes: 1
Views: 2506
Reputation: 2501
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);
}
Upvotes: 0
Reputation: 1437
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;
}
}
Upvotes: 1
Reputation: 1647
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... :-)
Upvotes: 1