I am using Primefaces 5.1 on glassfish 4. I have a view scoped bean behind an editable data table. As soon as the input text looses focus it returns to the old value and the cellEdit ajax event inside dataTable never fires.
For the last 2 weeks i have searched and tried numerous stackoverflow/ BalucC blog/ coderanch etc but I couldn't solve it. Input text simply does not retain the input. The edited text is actually present in the view because if i again try to edit the cell the edit value is there only until the input text has the focus.
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:form id="formbio">
<p:growl id="msgsbio" showDetail="true"/>
<p:contextMenu for="biolist" widgetVar="cMenu">
<p:menuitem value="Edit Cell" icon="ui-icon-search" onclick="PF('cellBio').showCellEditor();return false;"/>
<p:menuitem value="Hide Menu" icon="ui-icon-close" onclick="PF('cMenu').hide();"/>
</p:contextMenu>
<p:dataTable var="bres" value="#{aResultEntry.biolist}" id="biolist" editable="true" editMode="cell" widgetVar="cellBio" >
<f:facet name="header" >
<p:outputLabel value="Result input for Receipt # #{aResultEntry.voucher.receiptno}" />
</f:facet>
<p:ajax event="cellEdit" listener="#{aResultEntry.onCellEdit}" update=":allresulttabs:formbio:msgsbio"/>
<p:column headerText="Attribute" style="width:150px">
<h:outputText value="#{bres.testattribid.attributename}" />
</p:column>
<p:column headerText="Result" style="width:150px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{bres.resulttext}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{bres.resulttext}" style="width:100%" label="result"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
<p:commandButton actionListener="#{aResultEntry.saveBioGrid()}" value="Save" id="Savebtn" update=":allresulttabs:formbio:msgsbio" immediate="true" />
</h:form>
My view scoped managed bean
#Named("aResultEntry")
#ViewScoped
public class AResultEntry implements Serializable {
,,,,,,,
public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
Object evnt=event;
if(newValue != null && !newValue.equals(oldValue)) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Cell Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
......
}
Related
In my cell edit event in my backing bean, if the cell value is changed I want to update the value of another column as well of the datatable. The value is getting correctly set in my list object but is not getting reflected in my datatable. I tried updating using the datatable using RequestContext as well, but still the list is not getting refreshed. What am I doing wrong? Should I call any row event for this change?
Code snippet :
Bean
#Named("editView")
#ViewScoped
public class EditTableView implements Serializable {
private List<Cars> carList;
private List<String> brands;
#PostConstruct
public void init() {
brands = new ArrayList<String>();
brands.add("BMW");
brands.add( "Mercedes");
brands.add("Volvo");
brands.add("Audi");
brands.add("Renault");
brands.add("Fiat");
brands.add("Volkswagen");
brands.add("Honda");
brands.add("Jaguar");
brands.add( "Ford");
brands.add("Maruti Suzuki");
carList = new ArrayList<Cars>();
modifiedList = new ArrayList<Cars>();
Cars car =new Cars();
car.setCarId(1);
car.setBrand("BMW");
car.setColor("Grey");
car.setModelNumber("2323");
car.setSelfDriven("Y");
car.setYear("1980");
car.setStatus("");
carList.add(car);
}
public void onCellEdit(CellEditEvent event) {
int rowIndex = event.getRowIndex();
Cars car = null;
LOGGER.info("Car Edited"+rowIndex);
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
DataTable carTable = (DataTable) event.getSource();
String index = carTable.getClientId(FacesContext.getCurrentInstance());
LOGGER.info(index);
if(newValue != null && !newValue.equals(oldValue)) {
LOGGER.info("Cell Changed Old: " + oldValue + ", New:" + newValue);
car=carList.get(rowIndex);
carList.get(event.getRowIndex()).setStatus("Changed");
modifiedList.add(car);
}
}
}
xhtml
<h:form id="cellEditForm">
<p:dataTable id="cars" var="car" value="#{editView.carList}"
editable="true" editMode="cell" widgetVar="cellCars">
<f:facet name="header">Cell Editing</f:facet>
<p:ajax event="cellEdit" listener="#{editView.onCellEdit}"
update=":cellEditForm:cars" />
<p:column headerText="Id">
#{car.carId}
</p:column>
<p:column headerText="Model Name" style="background-color:yellow">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{car.modelNumber}" />
</f:facet>
<f:facet name="input">
<p:inputText id="modelInput" value="#{car.modelNumber}"
style="width:96%" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Year" style="background-color:yellow">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{car.year}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{car.year}" style="width:96%" label="Year" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Brand" style="background-color:yellow">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{car.brand}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{car.brand}" style="width:100%">
<f:selectItems value="#{editView.brands}" var="man"
itemLabel="#{man}" itemValue="#{man}" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Self Driven" style="background-color:yellow">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{car.selfDriven}" />
</f:facet>
<f:facet name="input">
<p:inplace>
<p:inputText value="#{car.selfDriven}" />
</p:inplace>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Color" style="background-color:yellow">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{car.color}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{car.color}" style="width:96%" label="Color" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<h:outputText value="#{car.status}" id="statusLabel"></h:outputText>
</p:column>
</p:dataTable>
</h:form>
I used jquery eventually. Got the index of the updated row and called jquery function from my bean.
RequestContext requestContext = RequestContext.getCurrentInstance();
String call = "updateCell(" + event.getRowIndex() + ")";
requestContext.execute(call);
Jquery code
function updateCell(i) {
var index = "cellEditForm:cars:"+i+":statusLabel";
document.getElementById(index).innerHTML="Changed";
}
OmniFaces has a great util for this, called 'Ajax'
A StackOverflow post about this shows how to use it: How to use OmniFaces Ajax.updateColumn() or Ajax.updateRow() via p:ajax
Update form not table or put table in panel and update panel.
to be safe
<h:form id="cellEditForm">
<p:panel id="something" styleclass="pero">
<p:dataTable id="cars
update="#(.pero)"
be sure to put id on panel because class update will search for that id and use it. This solution is because i don't know rest of the code and it is one that will work on any code.
I am attempting to make a nested (Through row expansion) data table editable which is inside of another editable datatable. It appears to be having a problem with the ajax rowEdit event. When I only have one datatable as editable e.g. comment out the nested ajax tag it works. But when I try to use both It returns an error saying :
Method not found: com.aglabexpress.Admin.Billing.CompleteInvoiceController#1146df77.editInvoiceItem(javax.faces.event.AjaxBehaviorEvent)"
Is this because of the double ajax events?
How do I rectify this while keeping both tables editable?
HTMLX:
<h:form id="mainForm" >
<p:dataTable id="mainFormTable" editable="true" value="#{completeInvoiceController.labNumberBill}" var="lab" paginator="true" rows="10" rowStyleClass="#{lab.colorStatus}">
<p:ajax event="rowEdit" listener="#{completeInvoiceController.editBill}" />
<p:column>
<p:rowToggler/>
</p:column>
...
...
<p:column headerText="Date" footerText="Date">
<p:cellEditor>
<f:facet name="output">
<p:outputLabel value="#{lab.creationDateString}" />
</f:facet>
<f:facet name="input">
<p:calendar value="#{lab.creationDate}" />
</f:facet>
</p:cellEditor>
</p:column>
...
...
<p:column headerText="Edit">
<p:rowEditor />
</p:column>
<p:rowExpansion>
<p:dataTable value="#{lab.invoiceItems}" var="item" editable="true">
<p:ajax event="rowEdit" listener="#{completeInvoiceController.editInvoiceItem}" />
...
...
<p:column headerText="Description" footerText="Description">
<p:cellEditor>
<f:facet name="output">
<p:outputLabel value="#{item.description}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{item.description}" />
</f:facet>
</p:cellEditor>
</p:column>
...
...
<p:column headerText="Edit">
<p:rowEditor />
</p:column>
</p:dataTable>
</p:rowExpansion>
Beans
public void editInvoiceItem(RowEditEvent event){
InvoiceItemConstructor itc = (InvoiceItemConstructor) event.getObject();
if(cih == null){
cih = new CompleteInvoiceHelper();
}
cih.updateItem(itc);
}
public void editBill(RowEditEvent event){
CompleteInvoiceLabNumberBill bill = (CompleteInvoiceLabNumberBill) event.getObject();
if(cih == null){
cih = new CompleteInvoiceHelper();
}
cih.updateBill(bill);
}
You need to replace your nested datatable event method signature to
public void editInvoiceItem(javax.faces.event.AjaxBehaviorEvent event)
Is this because of the double ajax events?
Yes. This is a known issue (which had been originally reported for nested p:tabView) which seems to be fixed since PrimeFaces 5.0.
You can find further information in a thread (from July 2013) of the PrimeFaces forum
I am using JSF Primefaces for my UI. I have a specific requirement about ajax on p:datatable. This is a sample page of my project:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:comp="http://java.sun.com/jsf/composite/components/">
<ui:define name="content">
<h:form id="form1">
<p:growl id="messages" showDetail="false" />
<p:panel header="Available Rows" style="width: 15%;">
<p:dataTable id="table" value="#{rowBean.rows}" var="row"
widgetVar="50" style="width: 60px;" editable="true">
<p:ajax event="rowEdit" listener="#{rowBean.onEdit}"
update="form1:messages" />
<p:ajax event="rowEditCancel" listener="#{rowBean.onCancel}"
update=":form1:messages" />
<p:column>
<f:facet name="header">
<h:outputText value="Row ID" />
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{row.id}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{row.id}"
style="width:100%" label="Row ID">
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Row Value" />
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{row.value}" />
</f:facet>
<f:facet name="input">
<p:inputText disabled="true" value="#{row.value}"
style="width:100%" label="Row Value">
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
<p:column style="width:6%">
<p:rowEditor />
</p:column>
</p:dataTable>
</p:panel>
<p:spacer height="5px;"/>
<p:panel id="createPanel" header="Create Row" closable="false" toggleable="true"
collapsed="true" style="width: 15%;">
<p:panelGrid columns="6">
<h:outputLabel for="rowBean" value="Row ID" />
<p:inputText value="#{rowBean.row.id}"
required="true" label="Row ID" style="width:125px" />
<h:outputLabel for="rowBean" value="Row Value" />
<p:inputText value="#{rowBean.row.value}"
required="true" label="Row Value" style="width:125px" />
<f:facet name="footer">
<p:commandButton value="Create" action="#{rowBean.createRow}"
update=":form1" />
</f:facet>
</p:panelGrid>
</p:panel>
</h:form>
</ui:define>
</ui:composition>
Here I have a data table which lists down all the rows created. Each row is having id and value. Value is editable. There is one more panel within the form which creates new rows. Backing bean is pre-populated with all the created rows with #PostConstruct. Backing bean is having other methods to edit, cancel and create. This page is working and given below is the new requirement.
In some cases there can be an error associated with each row. If there is an error attached with a row, then the value text needs to be updated like a link. While clicking on the link, the row ID and a parameter needs to be passed to backing bean. With these params, backing bean fetches the error details and passes it to the page. Then the error message needs to be shown on a pop-up.
Can you tell me how to do this?
On the XHTML side:
<p:messages id="messages" showDetail="true" autoUpdate="true" closable="true" />
On the JAVA side, in the function you call when you press the button:
if(error) {
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_WARN, "Error",
"Your error message."));
}
PD: This is my first answer, i'm getting used to the post options, i'm sorry if you dont see my message properly ;)
Maybe like this?:
<f:facet name="output">
<h:outputText value="#{row.value}" rendered="#{!row.hasError}" />
<h:commandLink value="#{row.value}" rendered="#{row.hasError}" command="#{row.command(parameters..)}" />
</f:facet>
I have datatable with celledit, the ajax event does not fire on cell edit. The event listener does not get called.Thanks.
<ui:define name="content">
<h:form prependId="false" id="tForm">
<p:datatable id="dTable" value="#{bean.tData}" var="data"
editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="#{bean.updateData(data)}" />
<p:column>
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{data.name}"></h:outputText>
</f:facet>
<f:facet name="input">
<p:inputText value="#{data.name}"></p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
</p:datatable>
</h:form>
</ui:define>
bean listener method
public void updateData(Data d){
logger.debug(d.getName());
}
I think you should use this instead:
<p:ajax event="cellEdit" listener="#{bean.updateData}" />
public void updateData(CellEditEvent event) {
Object newValue = event.getNewValue();
logger.debug(newValue.toString());
}
I have a JSF view that lists items in a collection in a Primefaces DataTable. The rightmost columns contain remove buttons. When a remove button is clicked, it is supposed to make an Ajax call, remove the corresponding item from the session variable Cart and update the view in-place. I would like the request and the view change to be as minimal as possible.
Here is what I have for this purpose:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Register user</title>
</h:head>
<h:body>
<f:view>
<h:form id="itemsForm">
<p:outputPanel id="items">
<p:dataTable value="#{cart.itemList}" var="item">
<p:column>
<f:facet name="header">
<h:outputText value="name" />
</f:facet>
<h:outputText value="#{item.product.description}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="quantity" />
</f:facet>
<h:outputText value="#{item.quantity}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="" />
</f:facet>
<p:commandButton icon="ui-icon-close" title="remove from cart">
<p:ajax listener="#{cart.removeItem}"
update="form:itemsForm"
process="#this" />
</p:commandButton>
</p:column>
<f:facet name="footer">
Total amount: ${cart.totalAmount}
</f:facet>
</p:dataTable>
</p:outputPanel>
</h:form>
</f:view>
</h:body>
</html>
Accordingly, I have the following method in Cart.java
public void removeItem() {
System.out.println("REMOVE REQUEST ARRIVED");
}
However, the removeItem method isn't even executing when I click a remove button.
So my questions are:
1) What is wrong with my Ajax call? What changes should I make to my XHTML?
2) How do I handle the request in the removeItem method and return a response?
3) How do I update the footer, which displays the totalAmount?
You can pass #{item} as a parameter of your method call in the actionListener.
Your .xhtml page should look like this:
<p:dataTable id="cartTable" value="#{cart.itemList}" var="item">
<p:column>
<f:facet name="header">
<h:outputText value="" />
</f:facet>
<p:commandButton icon="ui-icon-close" title="remove from cart"
actionListener="#{cart.removeItem(item)}" update="cartTable" />
</p:column>
</p:dataTable>
And this is the method removeItem of your ManagedBean:
#ManagedBean
#ViewScoped
public class Cart {
private List<Item> itemList;
public void removeItem(Item item) {
itemList.remove(item);
}
}
1) <p:commandButton uses ajax by default , so instead placing the p:ajax use the action or actionListener of the <p:commandButton
2) I would use the action of the button and return null
3) update="#form" should update the entire form and this will update the entire table
here an example of a working button (link) from my page , i used the f:setPropertyActionListener to "pass" some data to the delete method
<p:commandButton action="#{cart.removeItem}" icon="ui-icon-close" title="remove from cart" update="#form" process="#this" >
<f:setPropertyActionListener
target="#{cart.selectedItem}"
value="#{item}" />
</p:commandButton>
in your class add this
private Item selectedItem;
public Item getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(Item selectedItem) {
this.selectedItem = selectedItem;
}