Auto-updating filter values on DataTable - jsf

I'm currently using filters with options list on my lazy loaded DataTables. Everything works just fine except I'd like to be able to reload my filter options depending on currently selected filters.
For example, my DataTable has two fields country and region, and I want to filter
DataTable snippet :
<p:dataTable var="d" widgetVar="personneContactTable" value="#{bean.dataModel}" id="myDataTable" lazy="true">
<p:column sortBy="country" filterBy="country" filterOptions="#{bean.getCountryOptions()}">
[...]
</p:column>
<p:column sortBy="region" filterBy="region" filterOptions="#{bean.getRegionOptions()}">
[...]
</p:column>
</p:dataTable>
And my bean :
#ManagedBean(name = "bean")
#SessionScoped
public class MyBean implements Serializable {
LazyDataModel<MyStuff> dataModel;
String country;
String region;
public SelectItem[] getCountryOptions() {
return service.someMagic();
}
public SelectItem[] getRegionOptions() {
return service.someMoreMagic(country);
}
// + getters, setters, etc.
}
I tried using properties instead of methods, adding <p:ajax event="filter"> tags to try reloading part of the DataTable, but nothing worked. I found http://forum.primefaces.org/viewtopic.php?f=3&t=38087 too, but again not workable solution emerged.
How can I automaticaly refresh my filterOptions? (this is using Primefaces 4 ELITE branch)

Related

List in omnifaces.ListConverter is not set

I'm developing a JSF Application with PrimeFaces.
For a Picklist I'm trying to use the omnifaces.ListConverter but the list property in this converter is not set.
reporting-edit.xhtml
<p:pickList id="picklist_columns" value="#{reportingEditView.columns}" var="repcolumn"
itemLabel="#{repcolumn.column.name}" itemValue="#{repcolumn}" responsive="true"
showSourceFilter="true" filterMatchMode="contains">
<o:converter converterId="benni.ListConverter" list="#{reportingEditView.columns.source}"/>
<f:facet name="targetCaption">Spalten</f:facet>
<p:ajax event="transfer" listener="#{reportingEditView.handleColumnTransfer}"/>
reportingEditView.java
#ManagedBean
#SessionScope
public class ReportingEditView
{
private DualListModel<RepColumn> columns;
public void initPickList()
{
List<RepColumn> availableColumns = new ArrayList<>();
List<RepColumn> selectedColumns = new ArrayList<>();
... populate availableColumns and selectedColumns ...
this.columns = new DualListModel<RepColumn>();
this.columns.setSource(availableColumns);
this.columns.setTarget(selectedColumns);
}
}
All the columns are displayed in my PickList but when I put one column from the source list into the target list a NullPointer is thrown because the list in the converter is not set.
Also the listener Method is not called when transferring an element in the PickList.
Any ideas what I am doing wrong?
Shame on me!
I fixed that issue. I don't know how but there was xmlns:o="http://java.sun.com/jsf/core" in my reporting-edit.xhtml. After replacing that with xmlns:o="http://omnifaces.org/ui" everything works like a charm.

Primefaces dynamic columns p:columns sort specific columns

i have a datatable with dynamic columns, defined by a columnModel. The String property links to the correct field (used for value output). The sort String equals the property, but some columns should not be sortable, sort is null or emtpy (tried both) there:
public class ColumnModel {
private String property;
private String sort;
private int width;
//GETTER
...
}
I use a List of that models to create my dynamic columns. The use of the width is working well:
<p:dataTable value="#{bean.items}" var="item" ... >
<p:columns value="#{bean.columnModel}" var="column" sortBy="#{column.sort}" width="#{column.width}">
...
</p:columns>
</p:dataTable>
My Question:
sortBy does not allow a null or an emtpy value. Otherwise i get a parse exception where it says, it cannot parse #{item.}. primefaces seems to add 'item' (my var of the datatable) automatically before the given sortfield.
How can some columns be ignored?
Thanks for your answeres!
Using primefaces 5.0.9 with Wildfly 9.0.2
Primefaces added new attributes for p:column(s) in version 5.1.3 and 5.2.0:
sortable
filterable
Here is the link to the solved Issue:
https://code.google.com/archive/p/primefaces/issues/5021
Example depending on my code above:
public class ColumnModel {
private String property;
private boolean sortable;
private int width;
//GETTER
...
}
With a given List<ColumnModel> columnModel in bean:
<p:dataTable value="#{bean.items}" var="item" ... >
<p:columns value="#{bean.columnModel}" var="column" sortBy="#{item[column.property]}" field="#{column.property}" sortable="#{column.sortable}" width="#{column.width}">
...
</p:columns>
</p:dataTable>

Primefaces DataTable filter or paginator hinders the rendering of sequential fetch requests

I am working with Primefaces DataTable component. The user makes some city-district-service type choices before hitting the button and the datatable gets filled with the needed urban services (hospital, schools etc.), located at the needed spots of the city. The below code contains only the fetching button and the table itself.
When you fetch the first results you want, there isn't any problem. All is good, paginator works well. The problem starts when you filter the results by name. They actually get filtered very well too, BUT after a filtering is done; if you make other choices about the city, district or service and try fetching them; the columns of datatable gets filled with '| 0 | (empty) | (empty) |' rows (I guess its because the ID column is of type int and the other two are strings). Additional info: the number of the newly created empty rows are exactly equal to the former filter results.
I made the necessary debugging and found that at the backend everything is perfect. I get all my fetched objects. Actually when I type anything in the filter bar the new results become exposed too. It seems to be a problem totally in the client side rendering, though I couldn't find a way to solve it.
Any help would be greatly appreciated.
Update: After working on it for several more hours, I concluded that the reason might not be the filter but the paginator. Because when I turn off the paginator and get a full scrollable table, everything works perfectly well. Still not sure about the exact reason, so I edited the question subject according to that.
p.s: I'm using Primefaces 5.3, JSF 2.2 Mojarra, JDK 1.7, TomEE Plume
<p:commandButton action="#{filterByLocation.fetchServicesByLocation}" id="elbuton" value="Fetch" icon="ui-icon-check" onclick="PF('servisWidget').clearFilters();" update="servisList" />
<p:dataTable id="servisList" paginator="true" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}" rowsPerPageTemplate="5,10,15" rows="10" var="loc" value="#{filterByLocation.finalResults}"
widgetVar="servisWidget">
<p:column headerText="ID">
<h:outputText value="#{loc.id}" />
</p:column>
<p:column headerText="NAME" filterBy="#{loc.name}" filterFunction="#{filterByLocation.filterResults}">
<h:outputText value="#{loc.name}" />
</p:column>
<p:column headerText="SERVICE NAME">
<h:outputText value="#{loc.serviceName}" />
</p:column>
</p:dataTable>
My backing bean (getters/setters excluded for clarity):
#ManagedBean
#ViewScoped
public class FilterByLocation {
private List<LocationEntity> cities;
private List<LocationEntity> districtSelection;
private List<LocationEntity> finalResults = new ArrayList<LocationEntity>();
private List<Integer> selectedNodes = new ArrayList<Integer>();
private String filterText;
private String filterName;
private int city;
private int district;
public FilterByLocation() {
setCities(LocationTreeDAO.fetchCities());
}
public void listDistricts() {
setDistrictSelection(LocationTreeDAO.fetchDistricts(city));
}
public void selectNode(NodeSelectEvent node) {
TreeNode treeNode = node.getTreeNode();
LayerEntity layer = (LayerEntity) treeNode.getData();
selectedNodes.add(Integer.valueOf(layer.getId()));
}
public void unselectNode(NodeUnselectEvent node) {
TreeNode treeNode = node.getTreeNode();
LayerEntity layer = (LayerEntity) treeNode.getData();
selectedNodes.remove(Integer.valueOf(layer.getId()));
}
public void fetchServicesByLocation() {
setFinalResults(LocationTreeDAO.fetchFilteredServices(getCity(), getDistrict(), getSelectedNodes(), getFinalResults()));
setFilterText("");
}
public boolean filterResults(Object value, Object filter, Locale locale) {
setFilterText((filter == null) ? null : filter.toString().trim());
if (filterText == null || filterText.equals("")) {
return true;
}
if (value == null) {
return false;
}
String searched = value.toString().toUpperCase();
filterText = filterText.toUpperCase();
if (searched.contains(filterText)) {
return true;
} else {
return false;
}
}
Two screenshots depicting the situation
before
after
The filterFunction parameter of
<p:column ... filterFunction="#{filterByLocation.filterResults}" ...> is not necessary.
Change the statement to
<p:column headerText="NAME" filterBy="#{loc.name}" filterMatchMode="contains">
Add a List for the filtered values
<p:dataTable ... filteredValue="#{filterByLocation.filteredResults} ...>
#ManagedBean
#ViewScoped
public class FilterByLocation {
...
private List<LocationEntity> filteredResults;
...
}

Primefaces datatable's p:columns not iterating over Map

I am having a two level map Map<String,HashMap<String,String>> which i need to display using a <p:dataTable>. The code of managed bean is as follows:
#ManagedBean(name="MyBean")
public class MyBean{
private Map<String,HashMap<String,String>> twoDimentionalMap;
public void getMapData(){
twoDimentionalMap=getDataFromDataStore();
}
}
Now I am using this map in my view.xhtml file as follows:
<p:dataTable var="entrySet1" value="#{MyBean.twoDimentionalMap.entrySet()}">
<p:columns var="entrySet2" value="#{entrySet1.getValue()}">
#{entrySet2.getKey()} - #{entrySet2.getValue()}
</p:columns>
</p:dataTable>
I also tried using
<p:dataTable var="entrySet1" value="#{MyBean.twoDimentionalMap.entrySet()}">
<p:columns var="entrySet2" value="#{MyBean.twoDimentionalMap.get(entrySet1.getKey()).getValue()}">
#{entrySet2.getKey()} - #{entrySet2.getValue()}
</p:columns>
</p:dataTable>
I even tried converting the outer map to a list:
List<HashMap<String,String>> twoDimentionalMap;
However nothing is displayed on datatable. The execution shows no error but there is nothing displayed on the page.
Kindly suggest if I am doing something wrong or if <p:columns> is having any issue handling maps.
Thanks
since the keys of outer map do not have a meaning, converting the outer map to a list is correct.
but your approach to retrieve column names from xhtml does not seem valid. you need to get them independently from the current iteration variable entrySet1, otherwise you add a third dimension to the operation, which data table cannot handle.
we need to assume that all keys are same across the listed maps.
here is the code for xhtml:
<p:dataTable var="entrySet1" value="#{testMB.twoDimensionalMap}">
<p:columns var="keySet2" value="#{testMB.columnNames}">
#{keySet2} - #{entrySet1[keySet2]}
</p:columns>
</p:dataTable>
and for the bean:
#Named
#ViewScoped
public class TestMB implements Serializable {
private List<HashMap<String,String>> twoDimensionalMap;
public TestMB()
{
getMapData();
}
private void getMapData(){
//twoDimentionalMap=getDataFromDataStore();
twoDimensionalMap = new ArrayList<HashMap<String,String>>();
twoDimensionalMap.add(new HashMap<String,String>());
twoDimensionalMap.get(0).put("key0", "value00");
twoDimensionalMap.get(0).put("key1", "value01");
twoDimensionalMap.add(new HashMap<String,String>());
twoDimensionalMap.get(1).put("key0", "value10");
twoDimensionalMap.get(1).put("key1", "value11");
}
public Set<String> getColumnNames()
{
return twoDimensionalMap.size() > 0 ? twoDimensionalMap.get(0).keySet() : new HashSet<String>();
}
public List<HashMap<String, String>> getTwoDimensionalMap() {
return twoDimensionalMap;
}
}

h:commandButton inside h:dataTable [duplicate]

This question already has answers here:
How can I pass selected row to commandLink inside dataTable or ui:repeat?
(4 answers)
Closed 7 years ago.
I am using a JSF data table. One of the columns in the table is a Command button.
When this button is clicked I need to pass few parameters (like a value of the selected row) using the Expression language. This paramaters need to be passed to the JSF managed bean which can execute methods on them.
I have used the following snippet of code but the value i am getting on the JSF bean is always null.
<h:column>
<f:facet name="header">
<h:outputText value="Follow"/>
</f:facet>
<h:commandButton id="FollwDoc" action="#{usermanager.followDoctor}" value="Follow" />
<h:inputHidden id="id1" value="#{doc.doctorid}" />
</h:column>
Bean Method:
public void followDoctor() {
FacesContext context = FacesContext.getCurrentInstance();
Map requestMap = context.getExternalContext().getRequestParameterMap();
String value = (String)requestMap.get("id1");
System.out.println("Doctor Added to patient List"+ value);
}
How can I pass values to the JSF managed bean with a commandbutton?
Use DataModel#getRowData() to obtain the current row in action method.
#ManagedBean
#ViewScoped
public class Usermanager {
private List<Doctor> doctors;
private DataModel<Doctor> doctorModel;
#PostConstruct
public void init() {
doctors = getItSomehow();
doctorModel = new ListDataModel<Doctor>(doctors);
}
public void followDoctor() {
Doctor selectedDoctor = doctorModel.getRowData();
// ...
}
// ...
}
Use it in the datatable instead.
<h:dataTable value="#{usermanager.doctorModel}" var="doc">
And get rid of that h:inputHidden next to the h:commandButton in the view.
An -less elegant- alternative is to use f:setPropertyActionListener.
public class Usermanager {
private Long doctorId;
public void followDoctor() {
Doctor selectedDoctor = getItSomehowBy(doctorId);
// ...
}
// ...
}
With the following button:
<h:commandButton action="#{usermanager.followDoctor}" value="Follow">
<f:setPropertyActionListener target="#{usermanager.doctorId}" value="#{doc.doctorId}" />
</h:commandButton>
Related:
The benefits and pitfalls of #ViewScoped - Contains CRUD example using DataModel<E>.

Resources