Invalidate Primefaces's datatable row on row edition - jsf

I'm developing a web-app with JSF 2.1 + Primefaces 5.1. I have a datatable with row edition and each row has 2 inputText, 2 selectOneMenu and 1 selectBooleanCheckbox. I want to perform some business logic validation when clicking the check icon: it will validate the values of the 2 selectOneMenus. For that, I created a custom validator associated with the second selectOneMenu that validates both values:
<p:dataTable id="users_table_id" var="user" value="#{usersBean.users}" rowKey="#{user.id}" paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" emptyMessage="#{msgs.no_records}" sortBy="#{user.id}" sortOrder="ascending" rows="15" editable="true">
<f:facet name="header">
#{msgs.users}
</f:facet>
<p:ajax event="rowEdit" listener="#{usersBean.onRowEdit}" update=":users_form_id:growl"/>
<p:ajax event="rowEditInit" listener="#{usersBean.onRowEditInit}" update=":users_form_id:growl"/>
<p:ajax event="rowEditCancel" listener="#{usersBean.onRowEditCancel}" update=":users_form_id:growl"/>
<p:column headerText="#{msgs.id}" sortBy="#{user.id}" styleClass="centered-column">
#{user.id}
</p:column>
<p:column headerText="#{msgs.description}" sortBy="#{user.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.description}</f:facet>
<f:facet name="input"><p:inputText value="#{user.description}" styleClass="editable-cell"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.password}" sortBy="#{user.password}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.password}</f:facet>
<f:facet name="input"><p:inputText value="#{user.password}" styleClass="editable-cell"/></f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.sending_system}" sortBy="#{user.playerIn.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.playerIn.description}</f:facet>
<f:facet name="input">
<p:selectOneMenu binding="#{userPlayerInComponent}" styleClass="editable-cell" id="users_table_sending_system_id" value="#{user.playerIn}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}">
<f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/>
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.receiving_system}" sortBy="#{user.playerOut.description}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output">#{user.playerOut.description}</f:facet>
<f:facet name="input">
<p:selectOneMenu styleClass="editable-cell" id="users_table_receiving_system_id" value="#{user.playerOut}" effectSpeed="fast" filter="true" filterMatchMode="contains" converter="#{playerConverter}">
<f:selectItem itemLabel="#{msgs.select_option}" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItems value="#{usersBean.players}" var="player" itemValue="#{player}" itemLabel="#{player.description}"/>
<f:validator validatorId="userValidator"/>
<f:attribute name="userPlayerInComponent" value="#{userPlayerInComponent}"/>
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="#{msgs.active}" sortBy="#{user.active}" styleClass="centered-column">
<p:cellEditor>
<f:facet name="output"><p:selectBooleanCheckbox value="#{user.active}" disabled="true"/></f:facet>
<f:facet name="input"><p:selectBooleanCheckbox value="#{user.active}"/></f:facet>
</p:cellEditor>
</p:column>
<p:column styleClass="datatable-row-editor">
<p:rowEditor/>
</p:column>
<f:facet name="footer">
</f:facet>
</p:dataTable>
#FacesValidator("userValidator")
public class UserValidator implements Validator {
private static final Logger logger = LogManager.getLogger(UserValidator.class);
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
logger.entry(context, component, value);
if (value == null) {
return; // Let required="true" handle.
}
UIInput userPlayerInComponent = (UIInput)component.getAttributes().get("userPlayerInComponent");
if (!userPlayerInComponent.isValid()) {
return; // Already invalidated. Don't care about it then.
}
DtoPlayer playerIn = (DtoPlayer)userPlayerInComponent.getValue();
if (playerIn == null) {
return; // Let required="true" handle.
}
DtoPlayer playerOut = (DtoPlayer)value;
UsersBean usersBean = context.getApplication().evaluateExpressionGet(context, "#{usersBean}", UsersBean.class);
BigDecimal userId = usersBean.getUserEditingId();
logger.info(userId + " - " + playerIn.getDescription() + " - " + playerOut.getDescription());
for (DtoUser dtoUser : usersBean.getUsers()) {
if (!userId.equals(dtoUser.getId()) && dtoUser.getPlayerIn().equals(playerIn) && dtoUser.getPlayerOut().equals(playerOut)) {
logger.info("Invalidating...");
userPlayerInComponent.setValid(false);
FacesContext.getCurrentInstance().validationFailed();
throw new ValidatorException(new FacesMessage("BOOM!"));
}
}
logger.exit();
}
}
I was expecting that, when validation fails (and a ValidatorException is thrown), the datatable row would stay in edit mode and the two selectOneMenus highlighted with red colour. But what happens is that the row exits from edit mode, keeping the old values. If I edit it again, it displays the submitted values and the invalid cells are marked with red. And this behaviour continues as long as I try to submit the invalid values. If I close the edit mode, the invalid values are discarded and the row keeps only the old values (whether in view or edit mode).
How can I solve this? From the Primefaces' showcase, one can see that when you try to submit, let's say, a string with alfabetic characters in the year cell, the row keeps the edit mode and is highlighted. I want to achieve the same behaviour.

Related

Editing rows in p:dataTable

I try to update a datatable row with PrimeFaces 3.1.1 but it makes all values null.
public void onRowEdit(RowEditEvent event) {
Client us= (Client) event.getObject();
System.out.println("event edit"+us);
clientService.editClient( us );
FacesMessage msg = new FacesMessage("Client modifiƩ", ((Client) event.getObject()).getName_customer());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
This is my page xhtml:
<h:form>
<p:dataTable var="client" value="#{clientBean.clients}" widgetVar="clientTable" emptyMessage="No customers found with given criteria" filteredValue="#{clientBean.filteredClients}" paginator="true" rows="10" rowsPerPageTemplate="5,10,15" editable="true" id="testContainer">
<p:ajax event="rowEdit" update="#this" listener="#{clientBean.onRowEdit(event)}" />
<f:facet name="header"><p:outputPanel><h:outputText value="Recherche d'un client:" /> </p:outputPanel>
</f:facet>
<p:column filterBy="#{client.user.username}" headerText="Collaborateur" filterMatchMode="contains">
<h:outputText value="#{client.user.username}" />
</p:column>
<p:column filterBy="#{client.name_customer}" headerText="Nom" filterMatchMode="contains">
<f:facet name="output">
<h:link outcome="CustomerDetails?faces-redirect=true&includeViewParams=true" value="#{client.name_customer}" >
<f:param name="idCustomer" value="#{client.costumer_id}"></f:param>
<f:param name="nameCustomer" value="#{client.name_customer}"></f:param>
</h:link> </f:facet>
<f:facet name="input"><p:inputText value="#{client.name_customer}"/></f:facet>
</p:cellEditor>
</p:column>
<p:column filterBy="#{client.statut}" headerText="Statut" filterMatchMode="contains">
the problem is that your object Client us is null , try to display a property from your object us if is null so that will confirm that you don't get your object from your page correctly . So i suggest you to replace that :
<p:ajax event="rowEdit" update="#this" listener="#{clientBean.onRowEdit}" />
with that
<p:ajax event="rowEdit" update="#this" listener="#{clientBean.onRowEdit(event)}" />
Note that i just added the event property to onRowEdit.

Editor Calendar in Primefaces 3.5 cell value is lost?

is that I have a grid that dynamically genre, I mean I add empty rows to the grid, first thought to use primefaces in Cell Editor, so that the value is stored in the list of beans
List, works but the problem that I have is on the calendar, when I select one and is stored, it is stored in the list, I checked it does not execute the ajax event, you lose the value of the date.
<p:commandButton value="AƱadir dia" update="dataTable" actionListener="#{regDPNL.registrarNuevoDia}" />
<p:dataTable id="dataTable" var="dpnl" value="#{regDPNL.listdpnl}" paginatorPosition="top"
rows="20" rowIndexVar="rowIndex" editable="true" editMode="cell"
<p:ajax event="cellEdit" listener="#{regDPNL.onCellEdit}" />
<p:column width="25%">
<f:facet name="header">
<h:outputText value="NOMBRE" />
</f:facet>
<p:cellEditor>
<f:facet name="output"><p:inputText value="#{dpnl.nombre}" /></f:facet>
<f:facet name="input"><p:inputText value="#{dpnl.nombre}" /></f:facet>
</p:cellEditor>
</p:column>
<p:column width="20%">
<f:facet name="header">
<h:outputText value="DESDE" />
</f:facet>
<p:cellEditor>
<f:facet name="output"><p:inputText value="#{dpnl.fechaDesde}" /></f:facet>
<f:facet name="input"><p:calendar value="#{dpnl.fechaDesde}" pattern="dd/MM/yyyy" /></f:facet>
</p:cellEditor>
</p:column>
<p:column width="20%">
<f:facet name="header">
<h:outputText value="HASTA" />
</f:facet>
<p:cellEditor>
<f:facet name="output"><p:inputText value="#{dpnl.fechaHasta}" /></f:facet>
<f:facet name="input"><p:calendar value="#{dpnl.fechaHasta}" pattern="dd/MM/yyyy" /></f:facet>
</p:cellEditor>
</p:column>
<p:column width="5%">
<f:facet name="header">
<h:outputText value="ELIMINAR" />
</f:facet>
<p:commandButton icon="ui-icon-editar" title="Delete Periodo" style="background:#fff">
</p:commandButton>
</p:column>
</p:dataTable>
Java code:
private List<DetallePeriodoBean> listdpnl = new PeriodoNoLaborable();
private DetallePeriodoBean detallePeriodoNoLaborable = new ArrayList<DetallePeriodoBean>();
public void registrarNuevoDia() {
detallePeriodoNoLaborable = new DetallePeriodoBean();
this.listdpnl.add(detallePeriodoNoLaborable);
}
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if(newValue != null && !newValue.equals(oldValue)) {
System.out.println("==> Old: " + oldValue + ", New:" + newValue);
}
}
http://s2.subirimagenes.com/imagen/previo/thump_8690487captura.png
I have faced this problem.
The solution is very simple (after a lot of testing and error)
You must add id attribute to your tag,
for instance:
<p:calendar id="date_selector" value="#{dpnl.fechaHasta}" pattern="dd/MM/yyyy" />
At the facet named output use the tag h:outputText instead of p:inputText
make sure you use java.util.date for your date fields(i.e fechaDesde etc) in your bean.

p:dialog shows empty values when when I go to the next page of the p:datatable using paginator

I have been using onEdit in the p:datatable and it works fine.My data table has a pagintor and shows 5 records per page.so when I click on the onEdit in the first page event.getObject gets the changed value in the bean.Now when I go the next page the event.getObject does not work and returns the old value only.
Same with the dialog box.In the table I have a link when clicked opens a dialog box in whcih I am populating few fields with the values from the row selected.It works fine in the first page and When I navigate to other pages gives empty values.
Here is my jsf code:
<p:dataTable value="#{mybean.userList}"
var="item"
id="dataTab"
widgetVar="usersTable"
tableStyleClass="data" paginator="true" rows="5"
filteredValue="#{userController.filteredUsers}"
editable="true"
rowKey="#{item}"
>
<p:ajax event="rowEdit" listener="#{mybean.onEdit}" update=":userForm:growl" />
<p:ajax event="rowEditCancel" listener="#{mybean.onCancel}" update=":userForm:growl" />
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="('usersTable').filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column sortBy="#{item.firstName}" filterBy="#{item.firstName}"
filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<f:facet name="output">
<h:outputText value="#{item.firstName}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.firstName}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{item.lastName}" filterBy="#{item.lastName}" filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="Last Name" />
</f:facet>
<p:column headerText="Update" style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
<p:dialog id="modalDialog"
header="Delete User?"
modal="true"
resizable="false"
draggable="false"
widgetVar="delUserConf"
>
<h:panelGrid id="display" columns="2" style="width: 150px;">
<h:outputLabel value="Firat Name" style="font-weight: bold"/>
<h:outputText value="Last Name" style="border: none"/>
</h:panelGrid>
</p:dialog>
Here is the code in my bean for the edit functionality:
public String onEdit(RowEditEvent event)
{
User user=(User)event.getObject());
user.getFirstName();
}
I did not add the link that I have in my form which pops up the dialog.Also I read that this might be because of Lazy loading and I am not sure about it.I am populating my table with a list and not the model.
Could you let me know what should I do to make it work?
maybe you should switch to SessionBean scope because the scope view is released when there are changes in the view. Try SessionBean. Also you can call from view scope any sessionbean like this, where controladorMB is a sessionbean
public void detallesPersona() {
try {
FacesContext ctx = FacesContext.getCurrentInstance();
ValueExpression vex = ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(), "#{controladorMB}", ControladorMB.class);
ControladorMB gMB = (ControladorMB) vex.getValue(ctx.getELContext());
this.setSelectedPersona(gMB.getPersonaBean().detallesPersonas(this.selectedPersona.getIdPersona()));
} catch (Exception e) {
JsfUtil.addErrorMessage(e, "Error: " + e.getMessage());
}
}

event.getObject() in row editing for primefaces sends the old value to the bean

I am trying to use the feature of prime faces which allows user to edit the row data in the table itself.I have followed this link to achieve it:
http://www.primefaces.org/showcase/ui/datatableRowEditing.jsf
When I say edit user the new values which are entered are not sent to the bean.It still shows the old values only.
My code in JSF:
<p:dataTable value="#{mybean.userList}"
var="item"
id="dataTab"
widgetVar="usersTable"
tableStyleClass="data" paginator="true" rows="5"
filteredValue="#{userController.filteredUsers}"
editable="true"
rowKey="#{item}">
<p:ajax event="rowEdit" listener="#{mybean.onEdit}" update=":userForm:growl" />
<p:ajax event="rowEditCancel" listener="#{mybean.onCancel}" update=":userForm:growl" />
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="('usersTable').filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column sortBy="#{item.firstName}" filterBy="#{item.firstName}"
filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="First Name" />
</f:facet>
<f:facet name="output">
<h:outputText value="#{item.firstName}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.firstName}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column sortBy="#{item.lastName}" filterBy="#{item.lastName}" filterMatchMode="startsWith">
<p:cellEditor>
<f:facet name="header">
<h:outputText value="Last Name" />
</f:facet>
<p:column headerText="Update" style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
My code in bean:
public String onEdit(RowEditEvent event) {
User user=(User)event.getObject());
user.getFirstName();
}
code in the bean for getting the list in ui:
public List<UserBean> getUsersList(){
List<UserBean> retval = new ArrayList<>();
for (Object[] tuple : myFacade.getUserList()) {
UserBean ub = new UserBean();
ub.setFirstName((String) tuple[0]);
ub.setLastName((String)tuple[1]);
ub.setEmailAddress((String)tuple[2]);
ub.setOfficeNumber((String)tuple[3]);
ub.setRole((String)tuple[4]);
retval.add(ub);
}
return retval;
}
I have tried the suggestions that were given in some of the posts but they did not work.Could anyone let me know how can I get the new values.I am using glassfish 4.0,primefaces 3.5.
I was able to figure out the problem..Every time when I am getting the list in the getter method I am calling the database to load the data..But this should be done only if the list is null.The following code gives you a clear picture:
public List<UserBean> getUsersList(){
if(retval == null)
{
retval = new ArrayList<>();
for (Object[] tuple : myFacade.getUserList()) {
UserBean ub = new UserBean();
ub.setFirstName((String) tuple[0]);
ub.setLastName((String)tuple[1]);
ub.setEmailAddress((String)tuple[2]);
ub.setOfficeNumber((String)tuple[3]);
ub.setRole((String)tuple[4]);
retval.add(ub);
}
}
return retval;
}
So getUsersList is my value of var in the p:datatable and now when I call the onEdit it will check for the list if it is null it does a database call or does not call the database.

Row Editor does not update value object's fields displaying via "columns" tag

I try to devise flexible table containing dynamic columns for CRUD operations.
I use p:columns component to make dynamic columns, but those columns do not change value when I try to update it.
<h:form id="form">
<p:dataTable id="dataTable"
var="item"
value="#{tableEditorController.items}"
editable="true"
paginator="true"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15">
<p:ajax event="rowEdit" listener="#{tableEditorController.onEdit}" />
<f:facet name="header">
#{tableEditorController.tableName}
</f:facet>
<p:columns value="#{tableEditorController.columns}"
var="column"
columnIndexVar="colIndex">
<f:facet name="header">#{column.header}</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item[column.property]}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item[column.property]}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:columns>
<p:column>
<f:facet name="header">test</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item['activityName']}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item['activityName']}" style="width:100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Edit" style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
When I click on link in "Edit" column all the cells in selected row turn into text input fields.
If I edit a value in the "test" column and save, it saves properly as I expect.
But if I edit value using an input field in column which was generated by p:columns tag and try to save, it does not save changes.
I monitored http requests by Chrome Tools. The requests contain changed value in every case.
I ran my code under debugger and a RowEditEvent contains new data in first case and unchanged data object in second.
I cannot realize my mistake and only thing left I doubt is square braces notation.
I checked square braces notation using in "test" column and it works fine.
I use JSF 2.1.3 and Primefaces 3.3
Controller class is following:
#ManagedBean
#RequestScoped
public class TableEditorController {
private static List activityList;
static{
activityList = new ArrayList();
ActivityType at = new ActivityTypeImpl();
at.setActivityId(1L);
at.setActivityName("FirstActivity");
activityList.add(at);
at = new ActivityTypeImpl();
at.setActivityId(2L);
at.setActivityName("Second Activity");
activityList.add(at);
}
public void onEdit(RowEditEvent event){
FacesMessage msg = new FacesMessage("Row Edited");
msg.setDetail(event.toString() + event.getObject());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void delete(Object id){
}
public List getItems(){
return activityList;
}
public String getTableName(){
return "Name of the Table";
}
public List<ColumnModel> getColumns(){
ColumnModel m1 = new ColumnModel("ID", "activityId");
ColumnModel m2 = new ColumnModel("Activity", "activityName");
return Arrays.asList(m1, m2);
}
}
I will appreciate any suggestion and/or idea.
I have found a way around p:columns. I replaced it with following code.
<c:forEach items="#{tableEditorController.columns}" var="column">
<p:column>
<f:facet name="header">#{column.header}</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item[column.property]}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item[column.property]}" style="width:100%" disabled="#{not column.editable}"/>
</f:facet>
</p:cellEditor>
</p:column>
</c:forEach>
It works but I had to add JSTL library to project dependencies.

Resources