I have a dataTable which has cell editing and global filter capability:
<p:dataTable id="tbl01" value="#{userMappingBacking.staffList}" editable="true" editMode="cell" filteredValue="#{userMappingBacking.staffListFiltered}" var="s" rowKey="#{s.id}" widgetVar="tbl101WV">
...
<f:facet name="header">
<p:outputPanel>
<p:toolbar>
<p:toolbarGroup align="${text.line_start}">
<p:commandButton value="#{text.save}" action="#{userMappingBacking.saveChanges}" update="msgs"/>
</p:toolbarGroup>
<p:toolbarGroup align="${text.line_end}">
<h:outputText value="#{text.search_all_fields}:"/>
<p:spacer width="10"/>
<h:inputText id="globalFilter" onkeyup="PF('tbl101WV').filter()" />
</p:toolbarGroup>
</p:toolbar>
</p:outputPanel>
</f:facet>
...
<p:column headerText="#{text.user}" filterBy="#{s.userName}" filterable="false">
<p:cellEditor id="ceUser">
<f:facet name="output"><h:outputText value="#{s.userName}"/></f:facet>
<f:facet name="input">
<p:autoComplete id="acUser" dropdown="true" value="#{s.userName}" completeMethod="#{userMappingBacking.completeUnAssignedUser}"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
and the backing bean userMappingBacking supports all the methods and works fine.
My problem is quite strange, the <p:autoComplete id="acUser"... doesn't invoke the complete method unless a filter is applied to the table, after a filter application every thing works fine, but before that no values are completed in the p:autoComplete.
Could any one help or give an insight into this.
I actually found the problem to be in the backing bean, I had 3 lists:
staffList = new ArrayList<>();
staffListFiltered = new ArrayList<>();
userDTOList = new ArrayList<>();
that I fill in a viewAction listener
public void loadStaffListAction() {
staffList = zaties.listAllStaff();
staffListFiltered = zaties.listAllStaff();
userDTOList = iacw.listAllUsers();
}
the problem was having 2 different lists staffList and staffListFiltered filled with different objects from the service, so changing the code like this:
public void loadStaffListAction() {
staffList = zaties.listAllStaff();
staffListFiltered = staffList;
userDTOList = iacw.listAllUsers();
}
and this solved the problem, nevertheless this is not the best practice, as explained below.
Common Error:
in the primefaces showcase for filtered datatable the never initialize the filteredValue list to any thing, they leave it as null so the datatable filter logic initialize it in the right way, paying attention to this detail I advise:
Don't initialize any thing unless you get an error.
comments are welcome!
Related
I have a selectonemenu within a datatable column. The selected options are messed up when I delete a row and it doesn't seems to reflect the value in the backend bean. For example, I selected Item A in the first row, then add another row and select Item B in the second row, then when I delete the first row, the second row is move up with Item A selected, but the backend value of second row is still Item B and Item A is removed from the collection.
<p:dataTable id="insertDetailTable" styleClass="data-table"
rowIndexVar="rowIndex" var="receivingDetail"
value="#{receivingController.receiving.receivingDetails}">
<p:column headerText="Item">
<p:selectOneMenu styleClass="input" id="item"
value="#{receivingDetail.item}" required="true"
requiredMessage="Item is required" converter="itemConverter">
<f:selectItem itemLabel="Select an item" itemValue="#{null}"
noSelectionOption="true" />
<f:selectItems value="#{receivingController.items}" var="item"
itemLabel="#{item.code} - #{item.name}" itemValue="#{item}" />
<p:ajax update="insertDetailTable" />
</p:selectOneMenu>
</p:column>
<p:column styleClass="action-cell">
<f:facet name="header">
<p:commandButton icon="ui-icon-plus" value="Add"
action="#{receivingController.insertDetail('insert')}"
immediate="true" />
</f:facet>
<p:commandButton icon="ui-icon-trash"
action="#{receivingController.deleteDetail('insert', receivingDetail)}"
immediate="true">
<p:confirm header="Confirmation"
message="Do you wish to remove the selected detail?"
icon="ui-icon-alert" />
</p:commandButton>
</p:column>
</p:dataTable>
The backend code of adding a new row and deleting a row:
public void insertDetail(String owner) {
ReceivingDetail receivingDetail = new ReceivingDetail();
receivingDetail.setReceiving(receiving);
receivingDetail.setQtyStored(new BigDecimal("0.00"));
receiving.getReceivingDetails().add(receivingDetail);
RequestContext context = RequestContext.getCurrentInstance();
if (owner.equals(OWNER_INSERT)) {
context.update("insertForm");
context.execute("PF('insertDialogWV').show();");
} else if (owner.equals(OWNER_UPDATE)) {
context.update("updateForm");
context.execute("PF('updateDialogWV').show();");
}
}
public void deleteDetail(String owner, ReceivingDetail receivingDetail) {
receiving.getReceivingDetails().remove(receivingDetail);
ItemService itemSvc = (ItemService) getService(ItemService.class);
setItems(itemSvc.find());
RequestContext context = RequestContext.getCurrentInstance();
if (owner.equals(OWNER_INSERT)) {
context.update("insertForm");
context.execute("PF('insertDialogWV').show();");
} else if (owner.equals(OWNER_UPDATE)) {
context.update("updateForm");
context.execute("PF('updateDialogWV').show();");
}
}
Any idea what went wrong with my code?
I am using Primefaces 5 and JSF 2.2.
This is the first time I posting a question, not sure did I do it right, let me know if I need to correct anything, thanks in advance.
Edited:
Just in case this information is required, the datatable resides within a dialog as such.
<h:form id="insertForm">
<p:dialog id="insertDialog" widgetVar="insertDialogWV" modal="true"
draggable="false" resizable="false" header="Add Record"
closable="false">
</p:dialog>
</h:form>
Removed immediate="true" in the command button and it works, the table select and show the value according to the backend bean properly.
I've done some research and haven't been able to find anything that directly addresses the problem I've been having.
I have a DataTable column that is editable (by cell) and I have the ability to click on the cell, enter a new number in the cell editor box, but when I hit the cell editor closes but does not save the new value (same thing happens if you just click off and don't hit enter).
Here is the Code Snippet
<h:form>
<c:forEach items="#{extensionsBean.getPhases()}" var="phase">
<p:fieldset legend="#{phase.getPhaseName()}">
<p:dataTable value="#{extensionsBean.getActivities(phase)}" var="activity" editable="true" editMode="cell">
<p:column>
<f:facet name="header">
<h:outputText value="Actual Hours"/>
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{activity.getEstimateDetail().actualHours}"/>
</f:facet>
<f:facet name="input">
<h:inputText value="#{activity.getEstimateDetail().actualHours}" />
</f:facet>
</p:cellEditor>
//the rest of the closing tags are present
Any suggestions would be great! For the record, I have basically the exact same setup in a different xhtml page and I'm able to edit each of the cells without a problem. Not sure what's causing this one to bug out on me.
Add Ajax event cellEdit and store the values
Add ajax event celledit and where do you want save the value you can save it.
Code is below in my project
Xhtml page(Primefaces):
<p:dataTable var="my" value="#{java.custom_info}" editMode="cell" editable="true" style="font-size: 12px">
<p:ajax event="cellEdit" listener="#{java.custom_detail}"/>
<p:column style="background: white">
<h:outputText value="First Name"/>
</p:column>
<p:column style="background: white">
<p:cellEditor>
<f:facet name="output"> <h:outputText value="#{my.first}"/> </f:facet>
<f:facet name="input"><p:inputText value="#{my.first}" placeholder="Enter First Name" style="width:93%"/></f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
Java Class
public void custom_detail(CellEditEvent event){
String old_str = (String) event.getOldValue();
String first_name = (String) event.getNewValue();
System.out.println("update method reached..."+first_name);
FacesContext fc = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) fc.getExternalContext().getSession(false);
Query db = new Query();
Customer bean = new Customer();
if(session!=null){
if(((String)session.getAttribute("login"))!=null){
Calendar currentDate=Calendar.getInstance();
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String datenow=format.format(currentDate.getTime());
session.setAttribute("firstname", first_name);
session.setAttribute("modified_date",datenow);
bean.setFirst(first_name);
bean.setUsrid((String)session.getAttribute("user"));
bean.setUsr_modified(datenow);
db.update_personalinfo(bean);
}
}
}
I am using Primefaces 4.0 and JSF 2.2. When I make a DataTable with row Edit and I set a valdiationFailed() on the rowEdit event, the roweditor is closing, which I want to prevent.
I added an oncomplete js function like:
<p:ajax event="rowEdit" listener="#{customerUI.onInvoiceRowEdit}"
oncomplete="if(!args.validationFailed) {updateTable();}" update=":messages" />
My remote command is as follows:
<p:remoteCommand name="updateTable" update=":form:addressTabs:customerTable" />
So this keeps the editor when the validation fails, but now the editors accept and cancel buttons doesn't work, so does editing other things on the side until i do a manual refresh.
I just want the editor to stay when the validation fails and to correct the input, if the validation went good, the editor can be closed.
Anyone any solution to this?
So I had a tangentially related problem and this question helped me figure out a solution so I thought I should share it here in case someone else lands on this question with a similar issue and needs help.
So I had a dataTable and a rowEdit ajax call to a function when a cell within the row is edited, I also used a remoteCommand to update the dataTable after I make some changes in the DB. Problem was if the validation for the cell edit value failed the remoteCommand would refresh the form and the error messages would disappear before they could be read. I wanted the ajax call on rowEdit to only go through if there were no validation errors, otherwise I wanted to display the error message with the row editor still open. So I used the args.validationFailed parameter as shown in the question to prevent the remoteCommand from being executed in case the custom validator fails. The following is a basic example of what I did.
JSF page:-
<h:form id="form_name">
<p:remoteCommand name="refreshForm" update="#form" />
<p:dataTable id="table_id" var="varTableData"
value="#{bean.tablerows}"
editable="true">
<p:ajax event="rowEdit"
listener="#{bean.onRowEdit}"
oncomplete="if(!args.validationFailed) refreshForm()" />
<p:column>
<f:facet name="header">
<h:outputText value="Column Title" />
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{varTableData.someValue}" />
</f:facet>
<f:facet name="input">
<p:inputText id="cellId"
value="#{varTableData.someValue}"
label="Some Label" required="true" style="width:100%"
validator="#{bean.validationMethod}">
</p:inputText>
<p:message id="someMsg" for="cellId" />
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</h:form>
Custom Validation Method :-
public void validationMethod(FacesContext context, UIComponent comp, Object value) {
int someCellValue = (int) value;
if (someCellValue < 6) {
((UIInput) comp).setValid(false);
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Some error message",
"some error message");
context.addMessage(comp.getClientId(context), message);
}
}
Primefaces 3.5, Mojarra 2.1.14. This is my PF datatable, it contains one non-editable boolean column named 'automatic', and editable 'label' column:
<p:dataTable value="#{bean.contents}" paginator="true" var="row"
editable="true" editMode="cell" rows="25" rowsPerPageTemplate="10,25,50" id="list">
<p:column>
<f:facet name="header"><h:outputText value="header1" /></f:facet>
<p:selectBooleanCheckbox value="#{row.automatic}" disabled="true" id="isAutomatic"></p:selectBooleanCheckbox>
</p:column>
<p:column>
<f:facet name="header"><h:outputText value="header2" /></f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{row.label}"></h:outputText>
</f:facet>
<f:facet name="input">
<p:inputText value="#{row.label}"></p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
<p:ajax event="cellEdit" process="#this" listener="#{myBean.onEditLabel}" update="isAutomatic"/>
</p:dataTable>
Cell edit event listener:
public void onEditLabel(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
if(newValue != null && !newValue.equals(oldValue)) {
DataTable s = (DataTable) event.getSource();
MyEntity d = (MyEntity) s.getRowData();
try {
d.setAutomatic(false);
myDAO.save(d);
addMessage("Change saved!");
} catch (Exception ex) {
addErrorMessage("Label could not be saved!");
getFacesContext().validationFailed();
}
}
}
The cell editor works, sends data to listener, and it is correctly persisted to the database. The 'automatic' flag is also cleared by cell edit event listener, and gets correctly persisted to the database. The problem is that 'automatic' checkbox is not updated on the client.
I also tried
<p:ajax event="cellEdit" process="#this" listener="#{myBean.onEditLabel}" update="list"/>
which correctly updated the checkbox, but also causes focus to be lost, and wastes bandwidth.
How can I update just a specific cell after cellEdit event is fired?
You p:ajax tag is inside p:dataTable no in some specific row or column, so you cent so easy update some relative component id. You can with help of RequestContext update specific component in cell. So, remove update from p:ajax and add this to your onEditLabel method:
RequestContext.getCurrentInstance().update(
s.getClientId(FacesContext.getCurrentInstance()) +
":" + event.getRowIndex() +
":isAutomatic"
);
As you can see, id of component inside cell has row number before id you assigned.
I believe you can solve this without having to know the details of the ID of the component you wish to update. You can pass it as a parameter to the bean.
First, bind the component you wish to update. You don't actual need a bean to which this component is bound to. You just need to define some value which you can use to identify this component later in your JSF. So in your case, you would do something like:
<p:selectBooleanCheckbox binding="#{isAutomaticComponent}" value="#{row.automatic}" disabled="true" id="isAutomatic"></p:selectBooleanCheckbox>
Now access the component when you do your update. ie:
<p:ajax event="cellEdit" process="#this" listener="#{myBean.onEditLabel(isAutomaticComponent.clientId)}" />
Now you can update the component from your cellEdit event method without knowing the contents of the ID. ie:
public void onEditLabel(CellEditEvent event, String idOfComponentToUpdate) {
...
RequestContext.getCurrentInstance().update(idOfComponentToUpdate);
...
Salut :), iam a newbie in primefaces and ajax
Iam using primefaces 3.4, glassfish 3.1, jsf2.0 and ejb 3. I tried to implement primefaces showcase datatable rowediting. But when i validate the updated value into the datatable, i get the old value. This is my code :
<h:form id="form">
<p:growl id="messages" showDetail="true"/>
<p:dataTable var="item" value="#{jSFMBean.allContacts}" id="contactList" editable="true">
<p:ajax event="rowEdit" listener="#{jSFMBean.onEdit}" update="#this :form:messages" />
<p:ajax event="rowEditCancel" listener="#{jSFMBean.onCancel}" update=":form:messages" />
<p:column headerText="EMAIL" style="width:125px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{item.email}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.email}" label="EMAIL"/>
</f:facet>
</p:cellEditor>
</p:column><p:column headerText="Options" style="width:50px">
<p:rowEditor />
</p:column>
</p:dataTable>
<h:outputText value="#{jSFMBean.selectedContact.displayname}" />
the methods are :
public void onEdit(RowEditEvent event) {
this.session.updateContact((Contacts) event.getObject());
FacesMessage msg = new FacesMessage("Edition contact: ", ((Contacts) event.getObject()).getDisplayname());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
(Contacts) event.getObject() always get the old value :(. It's like the getter of the datatable fireup first before ajax update to the database.
what iam i doing wrong ? thank you for your help solving this .
Currently you're editing values within the object. It looks like you still need to make a call back to your database to update the value there.
It seems that whenever you need your dataTable you are getting it from your database and that's why event.getObject() always returns the old value.So in the getter of your datatable you need to add:
if (allContacts== null){
allContacts= (List<Contacts>) yourservice.getAll(); /*this refers to the function that get the list from the database*/
}
return allContacts;
I hope that may help you.
Most probably the problem is with your backing bean. if you have used #Named annotation instead of #ManagedBean (javax.faces.bean.ManagedBean) for your backing bean, you faces this kind of problems. Simply replace
#Named (value="YourBeanName")
with
#ManagedBean (name="YourBeanName")