TableState.getMultiSortMeta() on Primefaces 8 - sorting

I'm upgrading from Primefaces version 7 to version 8. There is no longer a getMultiSortMeta() method in the TableState model available under PrimeFaces 8. Does anyone know how can I replace the following method and get it working in PrimeFaces 8?
public void onSort(SortEvent event) {
List<SortMeta> sortMeta = ((DataTable)
event.getComponent()).getMultiSortMeta();
channelsViewConfig.setMultiSortMeta(sortMeta);
}

In Primefaces 8 sortMeta is no longer a List, but uses Map<columnKey,sortMeta> to fetch the sorted collection. This collection is obtained via the attribute sortMeta rather than using sortBy;
<p:dataTable id="resultedtable"
value="#{bean.member}" var="member"
styleClass="resultedTable" paginator="true"
paginatorPosition="bottom"
pageLinks="5"
rowsPerPageTemplate="5,10"
sortMode="multiple"
sortMeta="bean.preSortOrder">
<p:column id="column1" headerText="column1" sortBy="#{member.column1}">
<h:outputText value="#{member.column1}" />
</p:column>
<p:column id="column2" headerText="column2" sortBy="#{member.column2}">
<h:outputText value="#{member.column2}" />
</p:column>
The backing bean getter for the collection would look something like this:
public Map<String, SortMeta> getPreSortOrder() {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
DataTable datatable = (DataTable)
viewRoot.findComponent("resultedtable");
UIColumn sortColumn = datatable.getColumns().get(0); // Sortby - firstcolumn
String sortField = sortColumn.getClientId(); // SortField - firstcolumn
SortMeta sortMeta = new SortMeta(sortColumn.getColumnKey(),
sortField, SortOrder.ASCENDING, null
);
preSortOrder = new LinkedHashMap<String, SortMeta>();
preSortOrder.put(sortColumn.getColumnKey(), sortMeta);
return preSortOrder;
}

Related

Why does the ajax event not fire?

I've got a primeface tree in my application. I tried to load all data att once it it jsut to much 2500 object, only some are used. So I tried to implement som sort of lazy loading. The first level is loaded on start and I would like to load the neccessary data when expanding the node. I googled some examples and modified it for my purpose. But in my case the ajax does not fire. what am i missing here?
the xhtml part
<h:form>
<p:panel id="add_elev2list"
header="lägg till elev"
collapsed="true"
toggleable="true">
<p:tree value="#{bookb.root}"
var="node"
dynamic="true" >
<p:ajax event="select"
update="#this"
listener="#{bookb.onNodeSelect}"/>
<p:treeNode >
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
</p:panel>
</h:form>
Before loading the first level of tree is build by
public void triggerTreeBuild() {
root = new DefaultTreeNode("Root", null);
ObjectContainer localdb = dbConnector.connDB();
ObjectSet<sbasUserList> res;
Query query = localdb.query();
query.constrain(sbasUserList.class);
//query.descend("klass").constrain(true);
res = query.execute();
for(sbasUserList sbu : res ){
if(sbu.isKlass()) {
TreeNode node0 = new DefaultTreeNode(sbu.getGroupname(), root);
node0.getChildren().add(new DefaultTreeNode("head"));
}
}
localdb.close();
}
which works fine. The ajax event should trigger this but it don't happen.
public void onNodeSelect(NodeSelectEvent nee){
log("expand"); //wrapper for System.out.println ... for some sort of debugging.
sbasUserList sbu = (sbasUserList) nee.getTreeNode().getData();
String[] allstd = sbu.getAllusers().split(",");
ObjectContainer localdb = dbConnector.connDB();
for(String persnum : allstd){
nee.getTreeNode().getChildren().add( new DefaultTreeNode(
getUserbyPersnum(localdb,persnum).getRealname()));
}
localdb.close();
}
Any idea why?
Best regards
Ralf
using tomcat 7.0.52 JSf 2.2 and primefaces 4.0
Due to you did not set attribute selectionMode="single".
<p:tree value="#{treeBasicView.root}"
var="node"
dynamic="true"
selectionMode="single">
<p:ajax event="select" listener="#{treeBasicView.onNodeSelect}" />
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>

PrimeFaces autocomplete with omniFaces.ListConverter and ajax return null in backBean

I'm trying to do a country/state/city loader with autocomplete tag but this don't works. I already had done with SelectOneMenu tag and it's works fine, but now I'm trying to implement it with autoComplete and I can't make it work properly because the method that is in the ajax tag returns null
this is my XHTML
<p:outputLabel value="Region"/>
<p:autoComplete value="#{beanPersona.region}" completeMethod="#{beanPersona.listarRegion}"
var="region" itemLabel="#{region.nombre}" itemValue="#{region}"
forceSelection="true" autocomplete="true" dropdown="true" >
<o:converter converterId="omnifaces.ListConverter" list="#{beanPersona.listRegion}"/>
<p:ajax event="itemSelect" listener="#{beanPersona.onRegionChange}" process="#form"/>
</p:autoComplete>
and this is my Bean (Scoope is ViewScope and everithing else works fine)
public void onRegionChange(SelectEvent e) {
System.out.println(e.getObject());
this.region = (Region) e.getObject();
}
public List<Region> listarRegion(String filtro) {
List<Region> listaCompleta = (List<Region>) (List<?>) new Dml().list(new Region());
List<Region> lista = new ArrayList();
if(filtro.length() > 0)
for (Region objeto : listaCompleta) {
if(objeto.getNombre().toLowerCase().contains(filtro.toLowerCase()))
lista.add(objeto);
}
else
lista = listaCompleta;
return lista;
}
if you could help me I would appreciate it

Selection of extendedDataTable inside popupPanel not in Ajax Request Parameter

I am having a JSF page that contains a modal popupPanel from Richfaces and inside this popupPanel is an extendedDataTable. Now I want to have the user selection in my bean every time the user selects a new row. At first I want to show the code then I will explain the problem.
Part of the xhtml page with the popupPanel and the extendedDatatable:
<rich:popupPanel id="kontaktPanel" modal="true" onmaskclick="#{rich:component('kontaktPanel')}.hide()">
<rich:extendedDataTable
value="#{nachfrageBean.loadedKontakte}" var="kontakt"
selection="#{nachfrageBean.selection}" id="kontaktTable">
<rich:column>
<f:facet name="header">
<h:outputText value="#{messages['tabelle.kontakt.instknz']}" />
</f:facet>
<h:outputText value="#{kontakt.instKnz}" />
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="#{messages['tabelle.kontakt.name']}" />
</f:facet>
<h:outputText value="#{kontakt.name}" />
</rich:column>
<a4j:ajax execute="kontaktTable kontaktPanel" event="selectionchange" listener="#{nachfrageBean.selectedRecord}" />
</rich:extendedDataTable>
</rich:popupPanel>
Corresponding bean with the listener and the needed members:
public class NachfrageBean {
private KontaktDTO kontakt;
private List<KontaktDTO> loadedKontakte = new ArrayList<KontaktDTO>();
/** DOCUMENT ME! */
private Collection<Object> selection;
public Collection<Object> getSelection() {
return selection;
}
public void setSelection( Collection<Object> selection ) {
this.selection = selection;
}
public List<KontaktDTO> getLoadedKontakte() {
//contacts are successfully loaded
return kontaktBusiness.getAllKontakte( );
}
public KontaktDTO getKontakt() {
return kontakt;
}
public void setKontakt( KontaktDTO kontakt ) {
this.kontakt = kontakt;
}
public void selectedRecord( AjaxBehaviorEvent event ) {
UIExtendedDataTable dataTable = ( UIExtendedDataTable )event.getComponent();
Object originalKey = dataTable.getRowKey();
for( Object selectionKey : selection ) {
dataTable.setRowKey( selectionKey );
if( dataTable.isRowAvailable() ) {
// do something with the selection
}
}
dataTable.setRowKey( originalKey );
}
}
The listener gets called successfully when the user selects a row in the datatable, but the selection is null, so I am getting a NPE. And when I remove the popupPanel and have my extendedDatatable directly in my page, then it works fine. I am always printing out the request parameters and I can see that there are two missing parameters when I have the datatable inside the pupupPanel. These request parameters are:
mainForm:kontaktTable:wi =
mainForm:kontaktTable:si = 3,3|3||x
So outside the popup the selection from the kontaktTable gets submitted but inside the popupPanel not. Does anyone know whats wrong here?
I just found a solution here .
By default the rich:popupPanel will be attached to the body and not to the form. Adding domElementAttachment="form" to the popupPanel just did it.

How to use OmniFaces Ajax.updateColumn() or Ajax.updateRow() via p:ajax

I am attempting to use the Ajax.updateColumn() method of the OmniFaces 1.3 (SNAPSHOT) Ajax utility. More specifically, I want to replace the use p:ajax update=":pageContentPanel", which is an h:panelGroup (or p:outputPanel) which contains the following xhtml, with the use of Ajax.updateColumn(table, 1).
<h:dataTable id="dt_tripDates" style="width: 200px !important;"
var="tripDate" value="#{pf_ordersController.tripDates}">
<p:column style="text-align: right !important;">
<h:outputText id="rowNumber" value="#{tripDate.rowNumber}" />
</p:column>
<p:column style="text-align: center !important;">
<p:calendar id="tripDate" value="#{tripDate.tripDate}"
size="16" label="Trip Date"
pattern="MM/dd/yyyy" navigator="true"
onchange="changeOthersOnDateChange(this);">
<p:ajax partialSubmit="false" event="dateSelect"
listener="#{pf_ordersController.tripDateSelectedOnAddUsingTemplate}"
update=":pageContentPanel"/>
<f:convertDateTime pattern="MM/dd/yyyy" />
</p:calendar>
</p:column>
</h:dataTable>
In the bean, I have the following, which is referenced by p:ajax listener="...":
public void tripDateSelectedOnAddUsingTemplate(DateSelectEvent event) {
DateTime dt, today = DateTime.now(),
tripDateTime = new DateTime(event.getDate());
String clientId = event.getComponent().getClientId();
Integer pos = clientId.indexOf(":tripDate") - 1,
rowNumber = Integer.valueOf(clientId.substring(clientId.lastIndexOf(":", pos) + 1, pos + 1));
/*
* clientId = orderAddUsingTemplateForm:dt_tripDates:0:tripDate
* id = tripDate
*/
/*
* if tripDates in the list, that follow the argument tripDate in the list,
* have today's Date, then set them to the argument
*/
for (int i = rowNumber; i < nbrOfTripDates; i++) {
tripDates.get(i).setTripDate(tripDateTime.toDate());
}
// OmniFaces Ajax utility to update UIData columns
Ajax.updateColumn(tripDatesDataTable, 1);
}
While attempting to use Ajax.updateColumn(), I added "HtmlDataTable tripDatesDataTable" as an attribute to the bean.
The bean is JSF #SessionScoped managed bean. Please let me know how I can call Ajax.updateColumn() when p:ajax (belonging to p:calendar in xhtml above) is executed. Thanks.
The key point is that you've got to have a handle to the UIData component somehow so that you can pass it to Ajax#updateColumn(). In your particular case, easiest way would be to get it by event.getComponent() with help of Components#getClosestParent().
UIData tripDatesDataTable = Components.getClosestParent(event.getComponent(), UIData.class);
// ...
Ajax.updateColumn(tripDatesDataTable, 1);
Note that you can also just get the row number this way without the need to break down the client ID.
int rowNumber = tripDatesDataTable.getRowIndex();

JSF DataModel getRowData always return the first row (which has index zero)

I have rich:select component inside a rich:dataTable column.
I added a4j:ajax tag to handle onblur event , to process some values related to this selected row.
But this worked only correct for the first row of the datatable , in the second row it do the same as in the first row.
When I traced my code I found that the datamodel.getRowData() method return the first row always.
Also I found that the datamodel.getRowCount() return the correct number of rows.
BUT datamodel.getRowIndex() return ZERO always.
ANY help ???
Here is my ManagedBean code (the needed code only) **
#ManagedBean(name = "saleBacking")
#SessionScoped
public class SaleBacking implements Serializable{
private DataModel<SaleLine> model ;
public DataModel<SaleLine> getModel() {
if (model == null) {
model = new ListDataModel<SaleLine>(salesLines);
}
return model;
}
public void updateRowData(AjaxBehaviorEvent event)
{
currentSaleLine = (SaleLine)getModel().getRowData();
System.out.println("Row count= "+getModel().getRowCount() + " , Row index= " + getModel().getRowIndex()) ;// this always return the correct rowCount but the index equal Zero (the first row of the datamodel)
if(currentSaleLine.getItemId() != null && currentSaleLine != null)
{
currentSaleLine.setItemPrice(currentSaleLine.getItemId().getItemDefEndUserPrice());
currentSaleLine.setPl(currentSaleLine.getItemId().getItemDefEndUserPrice());
currentSaleLine.setQuantity(1d);
currentSaleLine.setNetValue(currentSaleLine.getItemPrice() * currentSaleLine.getQuantity()) ;
calculateTotalSale();
}
}
}
Sale.xhtml
<rich:dataTable value="#{saleBacking.salesLines}" var="line" rows="50" id="datatable">
<rich:column>
<f:facet name="header"><h:outputLabel value="#{msgs.item}" style="font-size:15px;"/></f:facet>
<rich:select enableManualInput="true"
value="#{line.itemId}"
clientFilterFunction="containsFilter"
converter="#{itemConverter}"
defaultLabel="please write the item name" onlistshow="alert('jhjhj');"
>
<f:selectItems value="#{saleBacking.items}" var="item" itemValue="#{item}" itemLabel="#{item.code} #{item.name}"/>
<a4j:ajax event="blur" execute="#this" listener="#{saleBacking.updateRowData}" render="datatable master2" oncomplete="document.getElementById('myform:datatable:#{line.viewNo-1}:price').focus();"/>
</rich:select>
</rich:column>
</rich:dataTable>
I haven't used this construct before, so I'm not sure. But try SaleLine
currentSaleLine = context.getApplication().evaluateExpressionGet(context,
"#{line}", SaleLine.class);
To check if it returns the current row.
#BalusC yesterday

Resources