PrimeFaces DataTable CellEdit get entity/object
Asked Answered
P

3

11

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. Of course there is event.getRowIndex, which I can then use with the List<>, but that is not always convenient. Is there perhaps another way to get the entity from CellEditEvent?

Plagal answered 4/9, 2013 at 10:34 Comment(0)
Y
29

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.

Yap answered 4/9, 2013 at 14:2 Comment(2)
Well I need the CellEditEvent, the most convenient would be to somehow also include the CellEditEvent as an argument along with an entity if possible. Resulting in a method: public void onCellEdit(CellEditEvent event, Entity entity). Else I will probably go with the first way.Plagal
You can't pass additional arguments. Related: #3909767 So yes, the first way is the way to go. You can if necessary hide that boilerplate code away into an utility method. Or, if you happen to use JSF utility library OmniFaces, just use Entity entity = Faces.evaluateExpressionGet("#{entity}").Yap
S
12

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 :)

Sliding answered 18/8, 2015 at 20:53 Comment(0)
L
0

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:

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();
}
Leaflet answered 18/1, 2018 at 18:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.