Display Column Total in Primefaces data table - datatable

The Primefaces table which will be filtered by different column attributes needs to have a summary row that will update its value as the user change the values in filters. Is there any way to do this?

Create a Column Group footer in the payments.xhtml:
<p:dataTable var="payments" value="#{testBean.payments}" filteredValue="#{testBean.filteredPayments}">
<p:column headerText="Payment status:" filterBy="#{payment.status}">
<h:outputText value="#{payment.status}"/>
</p:column>
<p:columnGroup type="footer">
<p:row>
<p:column colspan="6" headerText="Total: "/>
<p:column colspan="2" headerText="#{testBean.totalPaymentsSum}"/>
</p:row>
</p:columnGroup>
</p:dataTable/>
In the TestBean.java add a method as a getter to calculate the summary row:
List<Payment> payments;
List<Payment> filteredPayments;
public String getTotalPaymentsSum() {
int total = 0;
for(Payment payment : filteredPayments) {
total += payment.getAmount();
}
return new DecimalFormat("###,###.###").format(total);
}
For more filter option see the Datatable Filter showcase.
If you have a lot of data and you are using datatable Lazy loading, you can calculate the summary row in the load() or filter() method.

Related

h:dataTable Nested Sorting Issue

I have a sorting issue in a JSF h:dataTable.
I have to structure a table where the initial overall-sorting-criterion is a score-number in the first column.
If there are multiple entries with the same score, then those entries shall be sorted in function of a second column with names, which shall appear in alphabetical order.
If again there should be multiple entries with the same values in the first and second column, then those entries shall be sorted in function of a third column, which is a location name, which shall be listed again in alphabetical order.
If again there should be multiple entries with the same values in the first, second, and third column, then those entries shall be sorted in function of a fourth column, which is an age-number, which shall appear in ascending order.
I know that I can achieve the initial-sorting score-number with the "sortBy" attribute and sortingOrder=ascending. But I struggle with the other before mentioned sorting-requirements, which is where I am looking for help...Is there a way of doing this without having to use custom sort functions?
Here is the xhtml-code of the dataTable.
<h:dataTable value = "#{userData.employees}"
var = "employee"
styleClass = "employeeTable"
headerClass = "employeeTableHeader"
rowClasses = "employeeTableOddRow,employeeTableEvenRow"
sortBy=“#{employee.score}“ sortOrder=“ascending“>
<h:column>
<f:facet id = "header">score</f:facet>
#{employee.score}
</h:column>
<h:column>
<f:facet name = "header">Name</f:facet>
#{employee.name}
</h:column>
<h:column>
<f:facet name = "header">Location</f:facet>
#{employee.location }
</h:column>
<h:column>
<f:facet name = "header">Age</f:facet>
#{employee.age}
</h:column>
</h:dataTable>
TL;DR: You can do this by actually using the primefaces DataTable with sortMode="multiple" and sortBy="#{userData.employeeSortingMeta}" returning a List of org.primefaces.model.SortMeta instances.
First of all you'll have to convert your plain HTML JSF dataTable to a Primefaces Datatable, adding ID attributes to dataTable and columns plus adding sortBy attributes to each column:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:p="http://primefaces.org/ui">
<h:form id="frmEmployees">
<p:dataTable id="tblEmployees" value = "#{userData.employees}"
var = "employee"
styleClass = "employeeTable"
headerClass = "employeeTableHeader"
rowClasses = "employeeTableOddRow,employeeTableEvenRow"
sortBy=“#{userData.employeeSortingMeta}“ sortMode=“multiple“>
<p:column id="score" sortBy="#{employee.score}">
<f:facet id = "header">score</f:facet>
#{employee.score}
</p:column>
<p:column id="name" sortBy="#{employee.name}">
<f:facet name = "header">Name</f:facet>
#{employee.name}
</p:column>
<p:column id="location" sortBy="#{employee.location}">
<f:facet name = "header">Location</f:facet>
#{employee.location }
</p:column>
<p:column id="age" sortBy="#{employee.age}">
<f:facet name = "header">Age</f:facet>
#{employee.age}
</p:column>
</p:dataTable>
In your bean, create methods to build the sorting meta data:
private List<SortMeta> employeeSortingMeta;
public List<SortMeta> getEmployeeSortingMeta() {
return this.employeeSortingMeta;
}
#PostConstruct
public void initialize() {
employeeSortingMeta = new ArrayList<>(4);
employeeSortingMeta.add(createSortMeta("score", SortOrder.DESCENDING));
employeeSortingMeta.add(createSortMeta("name", SortOrder.ASCENDING));
employeeSortingMeta.add(createSortMeta("location", SortOrder.ASCENDING));
employeeSortingMeta.add(createSortMeta("age", SortOrder.ASCENDING));
}
private SortMeta createSortMeta(final String sortProperty, final SortOrder order) {
// find the sort column component
final UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
final String columnIdPrefix = "frmEmployees:tblEmployees:";
final UIColumn column = (UIColumn) viewRoot.findComponent(columnIdPrefix + sortProperty);
assert null != column : "wtf?";
// create sort meta
final SortMeta sortMeta = new SortMeta();
sortMeta.setSortBy(column);
sortMeta.setSortField(sortProperty);
sortMeta.setSortOrder(order);
return sortMeta;
}
That should be it.

How to Trigger Ajax To Load Nested Dropdowns After Loading A Form?

I have a button to display an edit dialog form with a selectOneMenu that holds prefix number values in it and, after selecting one of those prefix values, three selectCheckboxMenu are loaded with employees data. This is workinkg fine.
<p:outputLabel value="prefix" for="prefixo" />
<h:panelGroup>
<p:selectOneMenu id="prefixo" value="#{demandasController.selected.prefixo}" converter="prefixosConverter" filter="true" filterMatchMode="contains">
<f:selectItem itemLabel="#{adeBundle.SelectOneMessage}" itemValue="#{null}" />
<f:selectItems value="#{prefixosController.items}"
var="prefixoItem"
itemValue="#{prefixoItem}"
itemLabel="#{prefixoItem.prefixo} - #{prefixoItem.nomePrefixo}"
/>
<p:ajax event="valueChange" update="uorPosCollection uorPosCollection1 uorPosCollection2" listener="#{demandasController.changePrefixo}"/>
</p:selectOneMenu>
</h:panelGroup>
<p:outputLabel value="Executivo(s)" for="uorPosCollection" />
<p:selectCheckboxMenu id="uorPosCollection" value="#{demandasController.selected.uorPosCollection}" label="Executivo(s)" multiple="true" converter="uorPosConverter" filter="true" filterMatchMode="contains" >
<f:selectItems value="#{demandasController.availableExecutivos}"
var="uorPosCollectionItem"
itemValue="#{uorPosCollectionItem}"
itemLabel="#{uorPosCollectionItem.matricula} - #{uorPosCollectionItem.nome} (#{uorPosCollectionItem.prefixo.prefixo})" />
</p:selectCheckboxMenu>
<!-- analogous code ommited -->
The Listener:
public void changePrefixo(AjaxBehaviorEvent event) {
availableExecutivos = LoadExecutivosListCombo(super.getSelected().getPrefixo());
//analogous methods ommited
}
The methods to load the employees lists:
private List<UorPos> LoadExecutivosListCombo(Prefixos prefixos) {
List<SelectItem> listExecutivosCombo = new ArrayList<>();
List<UorPos> listExecutivos = uorPosFacade.findUorPosExecutivosByPrefixo(prefixos);
for (int i = 0; i < listExecutivos.size(); i++) {
listExecutivosCombo.add(new SelectItem(listExecutivos.get(i)));
}
return listExecutivos;
}
//analagous methods ommited
Native queries to retrieve database:
public List<UorPos> findUorPosExecutivosByPrefixo(Prefixos prefixo) {
return (List<UorPos>) getEntityManager().createNativeQuery("SELECT * FROM UorPos WHERE prefixo=9951", UorPos.class).setParameter(1, prefixo.getPrefixo()).getResultList();
}
//analagous methods ommited
But when editing a register that already has prefix and employee values (saved earlier by some user), the 3 selectCheckboxMenu are loaded showing (undesired) id's entity class name on its labels value and empty dropdowns:
e.g.: in the figure above, when the edit form was loaded, it shows the values saved earlier by some user: the prefix 9882 (displayed as expected) and the three (empty) dropdowns for employees (displayed with the undesired class names in it). If I select a different value than 9882, the dropdowns are (ajax) filled as expected and if I select 9882 again, the employees are displayed as expected (without the class names):
I'm trying to resolve it by activating the ajax as below, but don't know how to call it in the function:
<p:dialog onShow="CallAjaxFunction()" modal="true" >
<script>
function CallAjaxFunction() {
<!-- how to call the ajax here ? -->
alert("displaying after form was loaded.")
}
</script>
...
</p:dialog>
Does anyone knows how to trigger ajax to load nested dropdowns after loading a form?
Or if someone has any other solution to display the values in the labels (without the class name) and automattically load the nested dropdowns, I appreciate that.
Thanks in advance.
After researching, I've used the listener to update the combos, using for this the open ajax event in the dialog:
<p:dialog onShow="PF('prefixowv').selectValue(':selected').click();" update= DemandasEditForm:uorPosCollection DemandasEditForm:uorPosCollection1 DemandasEditForm:uorPosCollection2 />
And changed the ajax event to selectItem, instead of valueChange:
<p:selectOneMenu id="prefixo" value="#{demandasController.selected.prefixo}" converter="prefixosConverter" filter="true" filterMatchMode="contains">
<f:selectItem itemLabel="#{adeBundle.SelectOneMessage}" itemValue="#{null}" />
<f:selectItems value="#{prefixosController.items}"
var="prefixoItem"
itemValue="#{prefixoItem}"
itemLabel="#{prefixoItem.prefixo} - #{prefixoItem.nomePrefixo}"
/>
<p:ajax event="selectItem" update="uorPosCollection uorPosCollection1 uorPosCollection2" listener="#{demandasController.changePrefixo}"/>
</p:selectOneMenu>
Regards,

How to get RowIndex from the actual selected Column into my Bean?

I try to get the rowindex from the actual selected Column to unselect it with:
public void rowSelect(SelectEvent event) {
MyDataView selected = (MyDataView) event.getObject();
if (!selectedData.remove(selected)) {
selectedData.add(selected);
} else {
RequestContext.getCurrentInstance().execute("PF('datatTable').unselectRow(rowindex);");
}
}
}
I know it is easy to unselect a row with the UnselectEvent and press "crtl" but my Customers want to unselect a row with one click.
<p:dataTable widgetVar="datatTable" id="idDataTable" value="#{bean.dataview}" var="data" scrollable="true" scrollHeight="150"
rowSelectMode="add" selectionMode="multiple"
selection="#{sendGroupSmsSimple.selectedReceivers}" rowKey="#{bean.id}" filteredValue="#{data.filterData}" rowIndexVar="dataRowIndex">
<p:column id="recColumn" headerText="Name" filterBy="#{bean.fullname}" filterFunction="#{data.filterData}">
<h:outputText value="#{bean.fullname}"/>
</p:column>
<p:ajax event="rowSelect" listener="#{sendGroupSmsSimple.rowSelect}" process="#this" update="mainForm:updatePanel"/>
</p:dataTable>
I don't want to update my whole Form because I want the actual state of my scrollbar.
My actual Primefaces Version is 6.0.
Scope of my Bean is GroupedConversationScoped.
Thanks

How to validate p:pickList to require at least one selection

I have used column picklist to customize columns of table on page and I want to show dialog message (Atleast one column should be enabled) if user disables all the columns from picklist. That means user should keep atleast one column in enable box.
<p:dialog id="pickListDialog" header="Customize View"
widgetVar="dlg">
<h:panelGrid>
<p:pickList id="columnPickList"
value="#{Class_Name.columns}" var="col"
itemLabel="#{Class_Name.columnPickList.columnsDisplayMap.get(col)}"
itemValue="#{col}">
<f:facet name="sourceCaption">Disabled</f:facet>
<f:facet name="targetCaption">Enabled</f:facet>
</p:pickList>
<p:commandButton value="Submit"
actionListener="#{Class_Name.columnPickList.saveColumns}" onclick="return disableClick();"
ajax="false" />
</h:panelGrid>
</p:dialog>
Javascript method -
function disableClick(){
if (document.getElementById("form:columnPickList_target").value == ""){
alert("Please Select Atleast One Field");
return false;
}
}
Here I have used Javascript for this. But I want to do this by JSF .
can anyone please tell me ?
Case 1 : Using required attribute
<p:pickList id="columnPickList" required="true" requiredMessage="Atleast one column should be enabled"
value="#{Class_Name.columns}" var="col"
itemLabel="#{Class_Name.columnPickList.columnsDisplayMap.get(col)}"
itemValue="#{col}">
<f:facet name="sourceCaption">Disabled</f:facet>
<f:facet name="targetCaption">Enabled</f:facet>
</p:pickList>
Case 2 : Opening dialog from backing bean
public void saveColumns()
{
validateColumns();
//doSomthing
}
public void validateColumns() {
//check if picklist target is empty
if(columns.getTarget().size()==0)
{
//open dialog
message="Atleast one column should be enabled";
RequestContext.getCurrentInstance().execute("validationDialog.show()");
}
}
private String message; //getter and setter
dialog :
<p:dialog id="valid" widgetVar="validationDialog">
<p:outputLabel value="#{yourbean.message}" />
</dialog>

Problems with ajax in jsf updating an output text field

I'm new to JSF and in class we should just set up a little "Pizza-Service" with logins etc. On the Page where i want to prepare my Order as a user I've a data table (primeface data table) with 4 columns. The last one is for the number of pizza of the type in the current cell.
What I want: If I am typing in a Number i want to set up a current Order (works fine so far with ajax) in the same moment i just want to show the user the current price. This is the little thing that is not working.
When I am using the tag there is just nothing happening and if I am taking the tag I'm getting this mistake:
<f:ajax> contains an unknown id 'ausgabe' - cannot locate it in the context of the component menge
What I thought was take the ajax tag set up a function (take the current order) and render an output text where the calculated price is shown directly. I called those function in german so bestellungAufnehmen = takeOrder and preisBerechnen = calculatePrice.
Thanks if someone could help me!
Here is the xhtml:
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<p:dataTable id="table" var="pizza" value="#{model.getPizzen()}">
<p:column headerText="Nr">
<h:outputText value="#{pizza.nr}"/>
</p:column>
<p:column headerText="Artikel">
<h:outputText value="#{pizza.name}"/>
</p:column>
<p:column headerText="Preis">
<h:outputText value="#{pizza.preis}"/>
</p:column>
<p:column headerText ="Menge">
<h:inputText id="menge" value="#{bestellung.anzahl}">
<f:ajax event="keyup" render="ausgabe" listener="#{bestellung.bestellungAufnehmen(pizza)}"/>
</h:inputText>
</p:column>
</p:dataTable>
<h:outputLabel value="Zu Zahlen: "/>
<h:outputText id="ausgabe" value="#{bestellung.preisBerechnen()} €"/>
</h:form>
</h:body>
and here is the the Bean with those functions.
#Named
#SessionScoped
public class Bestellung implements Serializable {
private static int bstzaehler=0;
private int bstnr;
private Map<String,Bestellposten> posten;
private int anzahl;
public Bestellung(){
this.bstnr=++bstzaehler;
this.posten = new HashMap<>();
}
/**
* #return the bstnr
*/
public int getBstnr() {
return bstnr;
}
/**
* #param bstnr the bstnr to set
*/
public void setBstnr(int bstnr) {
this.bstnr = bstnr;
}
public void bestellungAufnehmen(Pizza pizza){
if(this.posten.containsKey(pizza.getName()) == false){
Bestellposten b = new Bestellposten(this.getAnzahl(), pizza);
this.posten.put(pizza.getName(),b);
} else {
if(this.getAnzahl() > 0 ){
Bestellposten tmp = this.posten.get(pizza.getName());
tmp.setMenge(this.getAnzahl());
} else {
this.posten.remove(pizza.getName());
}
}
System.out.println("groesse: "+posten.size());
System.out.println("akt preis: "+this.preisBerechnen());
}
/**
* #return the anzahl
*/
public int getAnzahl() {
return anzahl;
}
/**
* #param anzahl the anzahl to set
*/
public void setAnzahl(int anzahl) {
this.anzahl = anzahl;
}
public double preisBerechnen(){
double sum = 0.0;
for(String key : this.posten.keySet()){
Pizza tmp = this.posten.get(key).getPizza();
sum += tmp.getPreis() * this.posten.get(key).getMenge();
}
return sum;
}
}
Try giving the full qualified id for the component:
<h:form id="frmPizza">
<p:dataTable id="table" var="pizza" value="#{model.getPizzen()}">
<p:column headerText="Nr">
<h:outputText value="#{pizza.nr}"/>
</p:column>
<p:column headerText="Artikel">
<h:outputText value="#{pizza.name}"/>
</p:column>
<p:column headerText="Preis">
<h:outputText value="#{pizza.preis}"/>
</p:column>
<p:column headerText ="Menge">
<h:inputText id="menge" value="#{bestellung.anzahl}">
<f:ajax event="keyup" render=":frmPizza:ausgabe" listener="#{bestellung.bestellungAufnehmen(pizza)}"/>
</h:inputText>
</p:column>
</p:dataTable>
<h:outputLabel value="Zu Zahlen: "/>
<h:outputText id="ausgabe" value="#{bestellung.preisBerechnen()} €"/>
</h:form>
I think, you should use update attribute to update that outputText, like update=":FormId:ausgabe"
<f:ajax event="keyup"
render=":frmPizza:ausgabe"
listener="#{bestellung.bestellungAufnehmen(pizza)}"
update=":frmPizza:ausgabe" />
The solution of luiggi worked but i couldnt answer directly because of my "low-level" here.
Iam not on my computer right now but isnt "update" an attribute of p:ajax and not of f:ajax and is the same as render? but i will try it aswell later on.
thx!

Resources