I have a datatable which displays various entities based on a List<>. When I select a cell for editing I want to be able to also get the entity somehow in order to update it.
I have been struggling with this problem two and I didn't like depending the var name so I found this solution:
public void onCellEdit(CellEditEvent event) {
Entity entity =(Entity)((DataTable)event.getComponent()).getRowData();
}
note that the entity is updated can be merged directly into the DB, also you can still get the old value. PS: thank you @BalusC for everything :)
One way would be to programmatically EL-evaluate the current <p:dataTable var>
.
Given a
<p:dataTable value="#{bean.entities}" var="entity">
you could get it as follows
public void onCellEdit(CellEditEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
Entity entity = context.getApplication().evaluateExpressionGet(context, "#{entity}", Entity.class);
// ...
}
Another way, if you're not interested in the CellEditEvent
argument, would be to override the CellEditEvent
argument altogether by passing the currently iterated entity as argument instead:
<p:ajax event="cellEdit" listener="#{bean.onCellEdit(entity)}" />
with
public void onCellEdit(Entity entity) {
// ...
}
Please note that you cannot keep the CellEditEvent
and pass additional arguments. This answer would otherwise obviously have been given.
I liked @user1928596's answer so I extended it a bit to get the exact datapoint represented by the cell and update only that. This does couple the datatable column heading text to the backend code but I don't know of a better way to do this.
What really surprised me about the result is that when I edit the data in the datatable, the data in the backing bean is changed as well. I don't need cellEditEvent.getNewValue() because the data in the view is somehow bound to the data in the backing bean. I thought it was display-only. The log statement at the end of the onCellEdit() method was intended to show the old and new values for the Event object but it only shows the new value.
Here's the cell-editable datatable:
Here's the display code:
<p:dataTable id="facilitatorAdminEvents" var="event" value="#{testBean.facilitatorEvents}" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{testBean.editEvent}" update="facilitatorAdminEvents" />
<p:column headerText="Event Name"><p:cellEditor><f:facet name="output"><h:outputText value="#{event.name}"></h:outputText></f:facet><f:facet name="input"><p:inputText value="#{event.name}" style="width:100%" /></f:facet></p:cellEditor></p:column>
<p:column headerText="Start Date"><p:cellEditor><f:facet name="output"><h:outputText value="#{event.startdate}"><f:convertDateTime pattern="M/d/yyyy" /></h:outputText>
</f:facet><f:facet name="input"><p:calendar id="eventStartdate" value="#{event.startdate}" effect="fold" /></f:facet></p:cellEditor>
</p:column>
<p:column headerText="End Date"><p:cellEditor><f:facet name="output"><h:outputText value="#{event.enddate}"><f:convertDateTime pattern="M/d/yyyy" /></h:outputText>
</f:facet><f:facet name="input"><p:calendar id="eventEnddate" value="#{event.enddate}" effect="fold" /></f:facet></p:cellEditor>
</p:column>
<p:column headerText="Status"><p:cellEditor><f:facet name="output"><h:outputText value="#{event.status}" /></f:facet>
<f:facet name="input">
<p:selectOneMenu id="eventstatuses" value="#{event.status}" style="width: 100%; margin: auto; " scrollHeight="80" showHeader="false" label="Statuses">
<f:selectItems value="#{testBean.eventStatuses}" var="status" itemLabel="#{status}" />
</p:selectOneMenu>
</f:facet></p:cellEditor>
</p:column>
<p:column id="delete" style="text-align: center; vertical-align: middle; min-width: 54px; ">
<p:commandButton update="facilitatorAdminEvents" icon="ui-icon-close" actionListener="#{testBean.deleteEvent(event.id)}"></p:commandButton>
</p:column>
</p:dataTable>
And the onCellEdit method (which I named editEvent()):
public void editEvent(CellEditEvent cellEditEvent) {
Object newValue = cellEditEvent.getNewValue();
String columnHeader = cellEditEvent.getColumn().getHeaderText();
Event editedEvent = (Event) ((DataTable) cellEditEvent.getComponent()).getRowData();
Event eventBeforeEdit = null;
for (Event thisEvent : events) { // Find this event in the list of cached events.
if (editedEvent.getId() == thisEvent.getId()) {
eventBeforeEdit = thisEvent;
}
}
log.info("Updating event " + eventBeforeEdit + " to " + editedEvent);
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
String update = null;
if ("Event Name".equals(columnHeader)) {
update = "update events set name = '" + newValue + "' where id = " + editedEvent.getId();
} else if ("Start Date".equals(columnHeader)) {
update = "update events set startdate = '" + dateFormatter.format(newValue) + "' where id = " + editedEvent.getId();
} else if ("End Date".equals(columnHeader)) {
update = "update events set enddate = '" + dateFormatter.format(newValue) + "' where id = " + editedEvent.getId();
} else if ("Status".equals(columnHeader)) {
update = "update events set status = '" + newValue + "' where id = " + editedEvent.getId();
} else {
log.error("Unrecognized value " + newValue + " encountered during event edit.");
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Event Save Failure:", "Apologies but we were unable to parse your entry " + newValue);
FacesContext.getCurrentInstance().addMessage(null, message);
return;
}
try {
mysqlNamedParameterJdbcTemplate.update(update, new HashMap<String, String>());
} catch (DuplicateKeyException e) { // There may be an event with the same name.
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Event Save Failure:",
"That name has already been used for an archived or logically deleted event. " + "Please use a different name for the new event to avoid confusion.");
FacesContext.getCurrentInstance().addMessage(null, message);
return;
}
log.info("Event " + eventBeforeEdit + " updated to " + editedEvent);
loadEvents();
}