Dynamic columns in editable table primefaces - jsf

I have an editable table with dynamic columns. When I edit a row, all fields are displayed correctly. But when I click the 'save' icon, the value of my first element gets written to the wrong column.
Basically I have an undefined number of translation files and I want to display and edit them.
These files have content like
<entry key="contractlist_fleetmanager_status_ALL_STATUSES">All statuses</entry>
and for de
<entry key="contractlist_fleetmanager_status_ALL_STATUSES">Alle Zustände</entry>
Example I have 3 different translation files de, en and fr. The columns are as follows: en fr and de. But in the hashmap translation item, is get first de then some empty fields and then fr and en.
[de=Alle Zustände, null, null, null, null, null, null, null, null, fr=All statuses, en=All statuses, null, null, null, null, null]
When I debug and look into handleRowEdit, the selectedItem value is mixed up. The first element now has already the value of the en field in stead of the de field.
[de=All statuses, null, null, null, null, null, null, null, null, fr=All statuses, en=All statuses, null, null, null, null, null]
Is this caused by the fact that en is the first column (columns are: en fr de ) in my primefaces table?
How can I solve this?
This is my bean code
private TranslationItem selectedItem;
private List<TranslationItem> translationItems;
private List<ColumnModel> columns = new ArrayList<ColumnModel>();
public Translation() {
createDynamicColumns();
}
public String handleRowEdit(TranslationItem selectedItem) throws IOException {
setSelectedItem(selectedItem);
getLog().debug("rowedit");
return "";
}
public List<ColumnModel> getColumns() {
return columns;
}
public List<TranslationItem> getTranslationItems() throws IOException {
if (translationItems == null) {
translationItems = new ArrayList<TranslationItem>();
Properties[] props = new Properties[localeItems().length];
int i = 0;
for (String locale : localeItems()) {
FileInputStream in = new FileInputStream(SiteConfig.getInstance().getDefaultConfigPath() + File.separator
+ "language_" + locale + ".xml");
props[i] = new Properties();
props[i].loadFromXML(in);
in.close();
i++;
}
Enumeration<Object> keys = props[0].keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
i = 0;
Map<String, String> value = new LinkedHashMap<String, String>() {
#Override
public String put(String key, String value) {
return super.put(key, value);
}
};
for (String locale : localeItems()) {
value.put(locale, props[i].getProperty(key));
i++;
}
translationItems.add(new TranslationItem(key, value));
}
}
return translationItems;
}
public void createDynamicColumns() {
String columnTemplate = "";
for (String locale : localeItems()) {
columnTemplate += locale + " ";
}
String[] columnKeys = columnTemplate.split(" ");
columns.clear();
for (String columnKey : columnKeys) {
columns.add(new ColumnModel(columnKey, columnKey));
}
}
//inner class TranslationItem
public class TranslationItem {
private String key;
private Map<String, String> value;
public TranslationItem() {
}
public TranslationItem(String key, Map<String, String> value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Map<String, String> getValue() {
return value;
}
public void setValue(Map<String, String> value) {
this.value = value;
}
public String getValueLocale(String locale) {
return value.get(locale);
}
}
//inner class ColumnModel
static public class ColumnModel implements Serializable {
private String header;
private String property;
public ColumnModel(String header, String property) {
this.header = header;
this.property = property;
}
public String getHeader() {
return header;
}
public String getProperty() {
return property;
}
}
And this is my jsf code
<p:dataTable id="translationtable" styleClass="ptable100" var="translation" value="#{adminTranslation.translationItems}" width="100%" height="200" widgetVar="translation"
emptyMessage="#{msg.all_lists_no_records_found}" editable="true" rowKey="#{translation.key}" rowIndexVar="rowIndex" selection="#{adminTranslation.selectedItem}" selectionMode="single"
resizableColumns="true" sortMode="multiple"
paginator="true" rows="20" rowsPerPageTemplate="5,10,20,50,100" paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} #{msg.all_lists_numberOfRowsDisplayed_label} {RowsPerPageDropdown}"
>
<p:ajax event="rowEdit" listener="#{adminTranslation.onEdit}" update="translationtable" />
<p:columns value="#{adminTranslation.columns}" headerText="#{column.header}" var="column" columnIndexVar="colIndex"
sortBy="#{translation.value[column.property]}" filterBy="#{translation.value[column.property]}" filterMatchMode="contains"
filterPosition="top" filterStyle="float:right;width: 200px;" styleClass="ui-editable-column">
<p:column >
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{translation.value[column.property]}"/></f:facet>
<f:facet name="input"><h:inputText value="#{translation.value[column.property]}" styleClass="input ilarge" /></f:facet>
</p:cellEditor>
</p:column>
</p:columns>
<p:column >
<p:commandLink id="rowEditLink" actionListener="#{adminTranslation.handleRowEdit(translation)}" ajax="true" >
<p:rowEditor id="edit"/>
</p:commandLink>
</p:column>
</p:dataTable>
I use primefaces 3.2 on tomcat 7

Related

p:dataTable does not update on first attempt [duplicate]

This question already has an answer here:
How and when should I load the model from database for JSF dataTable
(1 answer)
Closed 3 years ago.
I have developed a dynamic table which should refill table at every request, the same function is being performed by the code as follows:-
html
<h:form id="form">
<p:outputLabel value="Client: " />
<p:inputText id="inp" value="#{test.id}" />
<p:inputText id="inp1" value="#{test.title}" />
<p:commandButton value="Call List" action = "#{liveRangeService.LiveRangeServicesss(10)}"/>
<p:commandButton value="Call List" action = "#{liveRangeService.LiveRangeServicesss(20)}"/>
<p:dataTable var="result" id="tbl" widgetVar="dtlTBL"
value="#{liveRangeService.tableData}"
filteredValue="#{liveRangeService.filteredData}"
paginator="false"
scrollable="true" rowIndexVar="rowindex" scrollHeight="500"
scrollRows="50" liveScroll="true"
filterDelay="1100"
>
<p:ajax event="rowSelect" listener="#{test.onRowSelect(rowindex)}" />
<f:facet name="header">
<p:outputPanel layout="inline" styleClass="tabSpacer">
<h:outputText value="Global Filter:" />
<p:inputText id="globalFilter" onkeyup="PF('dtlTBL').filter()" style="width:150px;margin-left:10px;"/>
</p:outputPanel>
</f:facet>
<p:column width="50">
<f:facet name="header">
<h:outputText value="Sr." />
</f:facet>
<p:commandButton value="#{rowindex}" style="width: 49px" action="#{test.onRowSelect(rowindex)}"/>
</p:column>
<p:columns value="#{liveRangeService.tableHeaderNames}"
var="mycolHeader"
width="#{colIndex==0?'10%':colIndex==1?'70%':colIndex==2?'10%':colIndex==3?'10%':'0'}"
columnIndexVar="colIndex"
sortBy="#{result[mycolHeader]}"
filterBy="#{result[mycolHeader]}"
filterMatchMode="contains"
>
<f:facet name="header">
<h:outputText value="#{mycolHeader}" />
</f:facet>
<h:outputText value="#{result[mycolHeader]}" />
<br />
</p:columns>
</p:dataTable>
</h:form>
#ManagedBean(name="liveRangeService", eager = true)
#Dependent
public class LiveRangeService implements Serializable {
private static List< Map<String, String> > tableData;
public static List< Map<String, String> > filteredData;
private static List<String> tableHeaderNames;
private String tableColWidths;
public List<Map<String, String>> getTableData() {
return tableData;
}
public List<String> getTableHeaderNames() {
return tableHeaderNames;
}
public LiveRangeService() {
}
public static void LiveRangeServicesss(int noOfRows) {
tableData = new ArrayList< Map<String, String> >();
filteredData = new ArrayList< Map<String, String> >();
tableHeaderNames = new ArrayList<String>();
tableHeaderNames.add("ID");
tableHeaderNames.add("Title");
tableHeaderNames.add("Opn_Amt");
tableHeaderNames.add("Smr_Amt");
for (int i = 0; i < noOfRows; i++) {
Map<String, String> playlist = new HashMap<String, String>();
playlist.put("ID", "101000" + i);
playlist.put("Title", "Share Capital - Mr. " + i);
playlist.put("Opn_Amt", "0");
playlist.put("Smr_Amt", "0");
tableData.add(playlist);
}
filteredData=tableData;
System.out.println("Filled " + filteredData.size() + ", " + noOfRows);
String dlgTBL="form:tbl";
PrimeFaces.current().ajax().update(dlgTBL);
}
public String getTableColWidths() {
return tableColWidths;
}
public void setTableColWidths(String tableColWidths) {
this.tableColWidths = tableColWidths;
}
public List<Map<String, String>> getFilteredData() {
return filteredData;
}
public void setFilteredData(List<Map<String, String>> filteredData) {
this.filteredData = filteredData;
}
}
#ManagedBean(name="test")
#SessionScoped
public class Test implements Serializable {
public String id;
public String title;
public Test() {
id="1";
title="Testing";
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void onRowSelect(int row) {
try {
String i="ID";
String t="Title";
String ci="id";
String ct="title";
this.getClass().getDeclaredField(ci).set(this, LiveRangeService.filteredData.get(row).get(i));
this.getClass().getDeclaredField(ct).set(this, LiveRangeService.filteredData.get(row).get(t));
PrimeFaces.current().ajax().update("form:inp");
PrimeFaces.current().ajax().update("form:inp1");
PrimeFaces.current().executeScript("PF('dlg').hide();");
} catch (Exception e) {
System.out.println("Error! " + e.getMessage() );
}
}
}
but the problem is that when the table is needed to be updated for other query, the call of function has to be done 2 times ie. i have placed two buttons, one pressing button 1, the table is populated with 10 rows and on pressing button 2, the table is populated with 20 rows. Each button is needed to be pressed two times to update the table.
Please advice.
i have just initialized the tables in Constructor, and all worked same as required.
#ManagedBean(name="liveRangeService")
#SessionScoped
public class LiveRangeService implements Serializable {
private List< Map<String, String> > tableData;
public List< Map<String, String> > filteredData;
private List<String> tableHeaderNames;
private String tableColWidths;
public List<Map<String, String>> getTableData() {
return tableData;
}
public List<String> getTableHeaderNames() {
return tableHeaderNames;
}
public LiveRangeService() {
tableData = new ArrayList< Map<String, String> >();
filteredData = new ArrayList< Map<String, String> >();
tableHeaderNames = new ArrayList<String>();
LiveRangeServicesss (-1, false);
System.out.println("in Constructor:");
}
public LiveRangeService(int noOfRows, boolean showDialogue) {
}
public void LiveRangeServicesss(int noOfRows, boolean showDialogue) {
tableData.clear();
tableHeaderNames.clear();
filteredData.clear();
tableHeaderNames.add("ID");
tableHeaderNames.add("Title");
tableHeaderNames.add("Opn_Amt");
tableHeaderNames.add("Smr_Amt");
for (int i = 0; i < noOfRows; i++) {
Map<String, String> playlist = new HashMap<String, String>();
playlist.put("ID", "101000" + noOfRows + i);
playlist.put("Title", "Share Capital - Mr. " + noOfRows + " - " + i);
playlist.put("Opn_Amt", "0");
playlist.put("Smr_Amt", "0");
tableData.add(playlist);
}
filteredData=tableData;
System.out.println("table size: " + tableData.size() + ", " + filteredData.size());
}

Columns (table body) not visible in datatable when using lazydatamodel

Using LazyDataModel does not display columns in the datatable.
I have implemented custom LazyDataModel and I have implemented load method init. However, when I pass the datamodel as a value to the datatable, the columns are not rendered/displayed. But when I pass it as a list, the columns are rendered/displayed.
My LazyDataModel class
public class SearchPmrLazyDataModel extends LazyBaseDataModel<SearchDTO> {
public SearchPmrLazyDataModel() {
}
public void setData() {
if (searchCriteria == null) {
searchCriteria = new PmrSearchCriteriaDTO();
}
setWrappedData(pmrService.searchPmr(searchCriteria, teamId));
}
#Override
public List<PmrSearchResultViewDTO> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
setData();
searchCriteria.setPageRequest(determinePage(first, pageSize));
List<PmrSearchResultViewDTO> data = this.cachedData;
// rowCount
int dataSize = data.size();
this.setRowCount(dataSize);
// paginate
if (dataSize > pageSize) {
try {
return data.subList(first, first + pageSize);
} catch (IndexOutOfBoundsException e) {
return data.subList(first, first + (dataSize % pageSize));
}
} else {
return data;
}
}
#Override
public void setRowIndex(int rowIndex) {
if (rowIndex == -1 || getPageSize() == 0) {
super.setRowIndex(-1);
}
else
super.setRowIndex(rowIndex % getPageSize());
}
#Override
public Object getRowKey(PmrSearchResultViewDTO obj) {
return obj.getId();
}
}
My bean
public LazyDataModel<SearchDTO> getCorresLazyDataModel(String selectedTabName, String selectedStateName, String selectedStateName2) {
//returns corresponding lazy data model according to a business logic
return getLazyDataModel(selectedTabName, selectedStateName, selectedStateName2);
}
My XHTML page
<p:dataTable
value="#{formBean.getCorresLazyDataModel(pmrStatusTab, pmrState, pmrState2)}"
var="pmr" id="pmrStatusResultTable#{pmrStatusTab}#{pmrState}"
widgetVar="pmrStatusResultTable#{pmrStatusTab}#{pmrState}"
style="overflow: auto; width: auto! important; table-width:fixed"
rows="10" rowKey="#{pmr.id}" rowStyleClass="odd, even"
reflow="true" scrollWidth="#{formBean.scrollWidth}"
scrollable="true" scrollRows="10" paginator="true" lazy="true"
selectionMode="single" selection="#{formBean.selectedPmr}">
<p:ajax event="rowSelect" process="#this"
listener="#{formBean.onRowSelect}" />
<p:columns value="#{formBean.columns}" var="column"
columnIndexVar="colIndex" sortBy="#{pmr[column.property]}"
sortable="true">
<f:facet name="header">
<h:outputText value="#{column.header}" />
</f:facet>
<h:outputText value="#{pmr[column.property]}" />
</p:columns>
</p:dataTable>
The columns are not rendered/displayed only if I pass datamodel directly. If I pass the value as list, they are displayed, is there anything which I am missing?

PrimeFaces Datatable: How to receive selected rows values?

I use Prime Faces 6.2 to make a data table with checked column:
<p:dataTable id="#{prefix}List"
value="#{tickets}"
lazy="true"
paginator="true"
paginatorTemplate="{FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="{startRecord}-{endRecord} из {totalRecords}"
rows="20"
rowKey="#{ticket.id}"
var="ticket"
emptyMessage="Записи в данной категории отсутствуют">
<p:ajax event="toggleSelect" listener="#{ticketForm.onAllSelect}" process="#this" partialSubmit="true" />
<p:ajax event="rowSelectCheckbox" listener="#{ticketForm.onSelect}" update=":protocolForm" />
<p:ajax event="rowUnselectCheckbox" listener="#{ticketForm.onUnselect}" update=":protocolForm" />
<p:ajax event="rowSelect" listener="#{ticketForm.onSelect}" update=":protocolForm" />
<p:ajax event="rowUnselect" listener="#{ticketForm.onUnselect}" update=":protocolForm" />
<p:column selectionMode="multiple" style="width:40px; text-align:center" />
More specifically, when a header checkbox is selected I want to receive all selected rows data on server-side and use IDs of each row. Also, there's logic that helps to resolve a goal of hidding/rendering a page button when at least one checkbox is selected.
For this purpose I need manualy intercept a row/checkbox selection event and record IDs from it when a button pushed, so I can't use selection attribute of dataTable using such logic.
On server-side I have several event-listeners:
private Set<AbstractMTSBUExportTicket> abstractMTSBUExportTickets = new HashSet<>();
public Set<AbstractMTSBUExportTicket> getAbstractMTSBUExportTickets() {
return abstractMTSBUExportTickets;
}
public void onSelect(SelectEvent event) {
abstractMTSBUExportTickets.add((AbstractMTSBUExportTicket) event.getObject());
}
public void onUnselect(UnselectEvent event) {
abstractMTSBUExportTickets.remove(event.getObject());
}
public void onAllSelect(ToggleSelectEvent event) {
// do smth
}
Unfortunately, ToggleSelectEvent has only information about data-table itself within.
None information about rows I couldn't find. Also I tried to add process="#this" partialSubmit="true" attributes but seems like they do different actions.
So, could you give me an example of how it's possible to retrieve such data from an event object?
Should I use another way to solve it? Thanks for your answers in advance.
You're use lazy dataTable and this doesn't stay the selection on page change.
You need set the selection param with a type of your collection
Implement getRowKey inside your LazyDataModel and remove rowKey="#{ticket.id}"
Selection with checkbox doesn't need selectionMode="multiple".
This param is only for multiple selection when click on the table row with CTRL is pressed
My sugestion is control your selected data manualy
XHTML file:
<p:dataTable id="#{prefix}List"
value="#{tickets}"
lazy="true"
paginator="true"
var="ticket"
selection="#{ticketForm.selectedTickets}"
emptyMessage="Записи в данной категории отсутствуют">
<p:ajax event="toggleSelect"
listener="#{ticketForm.onAllSelect}" partialSubmit="true"/>
<p:ajax event="rowSelectCheckbox"
listener="#{ticketForm.onSelect}" update=":protocolForm"/>
<p:ajax event="rowUnselectCheckbox"
listener="#{ticketForm.onUnselect}" update=":protocolForm"/>
<p:ajax event="rowSelect"
listener="#{ticketForm.onSelect}" update=":protocolForm"/>
<p:ajax event="rowUnselect"
listener="#{ticketForm.onUnselect}" update=":protocolForm"/>
<p:column selectionMode="multiple" style="width:40px; text-align:center" />
<!--other p:columns-->
</p:dataTable>
Managed bean:
public void onRowSelect(SelectEvent event) {
if (event != null && event.getObject() != null &&
event.getObject() instanceof Ticket) {
if (selectedTickets== null) {
selectedTickets= new ArrayList<Ticket>();
}
if (!selectedTickets.contains((Ticket) event.getObject())) {
selectedTickets.add((Ticket) event.getObject());
}
}
}
public void onRowUnselect(UnselectEvent event) {
if (event != null && event.getObject() != null &&
event.getObject() instanceof Ticket &&
selectedTickets != null && selectedTickets.contains((Ticket) event.getObject())) {
selectedTickets.remove((Ticket) event.getObject());
}
}
public void onAllRowsSelect(ToggleSelectEvent event) {
//This is the trick, you don't need receive a collection
if (event.isSelected()) {
selectedTickets = ticketService.getAllTickets();
} else {
selectedTickets = new ArrayList<Ticket>();
}
}
LazyDataModel implemention of getRowKey method:
public class LazyPragaModel extends LazyDataModel<Ticket> implements Serializable {
private TicketService ticketService;
private static final long serialVersionUID = 1L;
public LazyPragaModel(TicketService ticketService) {
this.ticketService= ticketService;
}
#Override
public Object getRowKey(Ticket ticket) {
return ticket!= null ? ticket.getId() : null;
}
#Override
public Praga getRowData(String rowKey) {
List<Ticket> tickets = (List<Ticket>) getWrappedData();
for (Ticket ticket: tickets) {
if (ticket.getId().toString().endsWith(rowKey)) {
return ticket;
}
}
return null;
}
#Override
public List<Ticket> load(int first, int pageSize, String sortField,
SortOrder sortOrder, Map<String, Object> filters) {
setRowCount(ticketService.countLazyRecords(filters).intValue());
List<Ticket> tickets = ticketService.listLazyRecords(first, pageSize,
sortField, sortOrder.name(), filters);
return tickets;
}
}
Sugestion for your service. Generic methods for lazy dataTables:
public List<T> listLazyRecords(int first, int pageSize, String sortField,
String sortOrder, Map<String, Object> filters) {
sortOrder = sortOrder != null ? sortOrder.contains("ASC") ? "ASC" :
sortOrder.contains("DESC") ? "DESC" : null : null;
String query = " FROM " + getType().getSimpleName() + " t " +
(filters.size() > 0 ? buildLazyFilters(filters) : "") +
(sortOrder != null ? " ORDER BY " + sortField + " " + sortOrder : "");
return getManager().createQuery(query, getType())
.setFirstResult(first).setMaxResults(pageSize).getResultList();
}
public Long countLazyRecords(Map<String, Object> filters) {
String query = "SELECT COUNT(x) FROM " + getType().getSimpleName() +
" x " + (filters.size() > 0 ? buildLazyFilters(filters) : "");
return getManager().createQuery(query).getSingleResult();
}
private String buildLazyFilters(Map<String, Object> filters) {
StringBuilder filterBuild = new StringBuilder("WHERE ");
for (Map.Entry<String, Object> filter : filters.entrySet()) {
if (filter.getValue().toString().chars().allMatch(Character::isDigit)) {
filterBuild.append("( " + filter.getKey() + " = " +
filter.getValue() + " OR ");
}
filterBuild.append(filter.getKey() + " LIKE '%" +
filter.getValue().toString() + "%'");
filterBuild.append(filter.getValue().toString().chars()
.allMatch(Character::isDigit) ? ") ": "");
filterBuild.append(!filters.values().toArray()[filters.size() - 1]
.equals(filter.getValue()) ? " AND " : "");
}
return filterBuild.toString();
}
I think you are missing some things on the datatable.
Showcase: https://www.primefaces.org/showcase/ui/data/datatable/selection.xhtml
You need to add selectionMode=multiple and a selection=collection to gather the selected rows like...
<p:dataTable id="multipleDT"
var="car"
value="#{dtSelectionView.cars4}"
selectionMode="multiple"
selection="#{dtSelectionView.selectedCars}"
rowKey="#{car.id}">
Whenever you select a row or row(s) the #{dtSelectionView.selectedCars} collection will be filled with the selected rows automatically.

Rowkey is null when celledit with LazyDataModel

I am using PrimeFaces 6.1. I have implemented LazyDataModel and I am able to load the rows, owever, when I update a cell, the method onCellEdit is called but event.rowKey is always null.
<p:dataTable emptyMessage="Nessun record trovato."
style="margin-top: 50px" id="cars" var="produit"
value="#{gecomparBean.lazyModel}"
editable="true" editMode="cell" widgetVar="carsTable"
filteredValue="#{gecomparBean.filteredCars}"
rows="10"
lazy="true"
scrollRows="10"
scrollable="true" liveScroll="true" scrollHeight="250"
resizableColumns="true" resizeMode="expand"
draggableColumns="true"
rowStyleClass="#{produit.id == gecomparBean.selectedObject.id ? 'selectedRow' : null}"
>
<p:ajax event="colReorder"
listener="#{gecomparBean.onColumnReorder}" />
<p:ajax event="cellEdit" listener="#{gecomparBean.onCellEdit}"
oncomplete="updateTable()" update=":form:remote" />
Managed Bean: [Session scoped]
wrapper.setSession(activeSession.getId());
lazyModel = new LazyProductDataModel(wrapper);
LazyProductDataModel
public class LazyProductDataModel extends LazyDataModel<ProductSessionDTO> implements Serializable {
private List<ProductSessionDTO> products;
private ProductSearchWrapper wrapper;
public LazyProductDataModel(ProductSearchWrapper wrapp) throws RestRequestException {
super();
wrapper = wrapp;
}
#Override
public ProductSessionDTO getRowData(String rowKey) {
for (ProductSessionDTO car : getProducts()) {
if (car.getId() == (Long.parseLong(rowKey))) {
return car;
}
}
return null;
}
#Override
public Object getRowKey(ProductSessionDTO car) {
return car.getId();
}
#Override
public List<ProductSessionDTO> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
List<ProductSessionDTO> data = new ArrayList<ProductSessionDTO>();
try {
System.out.println("First " + first + " Max " + pageSize);
wrapper.setFirst(first);
wrapper.setPageSize(pageSize);
products=ServiceUtils.getInstance().getProducts(wrapper);
if (getProducts() != null) {
Comparator<ProductSessionDTO> lengthComparator = new Comparator<ProductSessionDTO>() {
#Override
public int compare(ProductSessionDTO o1, ProductSessionDTO o2) {
return Long.compare(o1.getId(), o2.getId());
}
};
Collections.sort(products, lengthComparator);
}
} catch (RestRequestException ex) {
Logger.getLogger(LazyProductDataModel.class.getName()).log(Level.SEVERE, null, ex);
}
data = products;
//rowCount
int dataSize = data.size();
this.setRowCount(1000);
//paginate
if (dataSize > pageSize) {
try {
return data.subList(first, first + pageSize);
} catch (IndexOutOfBoundsException e) {
return data.subList(first, first + (dataSize % pageSize));
}
} else {
return data;
}
}
}
Note: I found a post which mentioned that we need to remove the rowkey in order for the getRowKey() to get called automatically - so I have removed that attribute.

h:selectBooleanCheckbox being selected in rich:dataTable is lost when using Pagination

I have list of h:selectBooleanCheckBox in rich:dataTabe. Also, there is pagination for the datatable.
The problem is when I click the next page number, the selected checkboxes at the first page of the datatable is gone. Though they are selected, clicking the next/previous page make them deselected.
Any idea about the problem?
These are the annotations for bean.
#ManagedBean(name = "bean")
#ViewScoped
To clarify it, I've attached my facelets and bean code below:
<rich:dataTable value="#{bean.ssTable}" var="data" iterationStatusVar="it" id="myDataTable">
...
<rich:column id="includeInWHMapping" >
<f:facet name="header">
<h:selectBooleanCheckbox value="#{bean.selectAll}" valueChangeListener="#{bean.selectAllCheckBox}">
<f:ajax render="myDataTable" />
</h:selectBooleanCheckbox>
</f:facet>
<h:selectBooleanCheckbox id="selectedForWHProcess" value="#{bean.checked[data]}">
<f:ajax actionListener="#{bean.selectAllRows}" />
</h:selectBooleanCheckbox>
</rich:column>
...
</rich:dataTable>
Bean code:
private Map<StandardStructure, Boolean> checked = new HashMap<StandardStructure, Boolean>();
private boolean selectAll;
/* Controller */
public MyController() {
super(new DataSetParameters());
logger.info("StandardStructureController created.");
Column rowid_col =new Column("rowid", "rowid", "No.", FilterTypes.NUMERIC, true, true, "");
Column fileid_col =new Column("fileid", "fileid", "File ID", FilterTypes.STRING, true, true, "");
Column releasetag_col =new Column("releasetag", "releasetag", "Releasetag ID", FilterTypes.STRING, true, true, "");
Column applicationid_col =new Column("applicationid", "applicationid", "Application ID", FilterTypes.STRING, true, true, "");
Column filename_col =new Column("filename", "filename", "Filename", FilterTypes.STRING, true, true, "ASC");
Column includeInWHMapping_col =new Column("includeInWHMapping", "includeInWHMapping", "Include in WH Mapping?", FilterTypes.NONE, true, true, "");
columns.put("fileid", fileid_col);
columns.put("releasetag", releasetag_col);
columns.put("applicationid", applicationid_col);
columns.put("filename", filename_col);
columns.put("includeInWHMapping", includeInWHMapping_col);
initialize();
setOrderField("importDate");
setOrder("DESC");
dataSetParameters.setColumns(columns);
loadTable();
}
/** getter/setter.. */
public boolean isSelectAll() {
return selectAll;
}
public void setSelectAll(boolean selectAll) {
this.selectAll = selectAll;
}
public Map<StandardStructure, Boolean> getChecked() {
return checked;
}
public void setChecked(Map<StandardStructure, Boolean> checked) {
this.checked = checked;
}
/** Load ssTable */
private void loadTable() {
try{
ssTable = new StandardStructureDao(dataSetParameters).getAllStandardStructure();
}catch (Exception ex){
System.out.println("Exception in loading table:"+ex);
}
}
/** Get ssTable */
public Collection<StandardStructure> getSsTable(){
return ssTable.getDto();
}
/** Pagination */
public void doPaginationChange(ActionEvent event) {
super.doPaginationChange(event);
loadTable();
/* trying to set the value of list of checkboxes after loading the table */
Iterator<StandardStructure> keys = checked.keySet().iterator();
while(keys.hasNext()){
StandardStructure ss = keys.next();
if(checked.get(ss)){ /* getting checked boxes */
/* Got stuck here. */
/* How do we just set the true (boolean) value only
for list of checkboxes though they are in Map?*/
System.out.println("Row id: " + ss.getRowid() + " Checked : " + checked.get(ss));
}
}
}
/** Select all the list of checkbox in datatable */
public void selectAllCheckBox(){
for(StandardStructure item : ssTable.getDto()){
if(!selectAll)
checked.put(item, true);
else
checked.put(item, false);
}
}
/** Select row of data in datatable */
public void selectAllRows(ValueChangeEvent e) {
boolean newSelectAll = (Boolean) e.getNewValue();
Iterator<StandardStructure> keys = checked.keySet().iterator();
logger.info("Rows selected..." + newSelectAll);
while(keys.hasNext()) {
StandardStructure ss = keys.next();
checked.put(ss, newSelectAll);
System.out.println("File::"+ss.getRowid()+":"+newSelectAll);
}
}
Many Thanks!
Since your code is unclear and confusing, I'll provide you the minimal example how pagination with select all on current page MIGHT look like. With no action listeners, just getters and setter. As simple as I could.
First XHTML:
<h:form>
<rich:dataTable value="#{bean.valuesOnPage}" var="data" id="dataTable" rows="20">
<rich:column>
<f:facet name="header">
<h:selectBooleanCheckbox value="#{bean.selectAll}">
<f:ajax render="dataTable" />
</h:selectBooleanCheckbox>
</f:facet>
<h:selectBooleanCheckbox value="#{bean.checked[data]}">
<f:ajax />
</h:selectBooleanCheckbox>
</rich:column>
<!-- other columns -->
</rich:dataTable>
</h:form>
Then the bean:
#ManagedBean(name = "bean")
#ViewScoped
public class MyBean {
// when the view is first loaded this is empty
// until someone will click one of checkboxes
private Map<Object, Boolean> checked = new HashMap<Object, Boolean>();
private boolean selectAll;
private List<Object> valuesOnPage;
private int currentPage = -1;
MyBean() {
setCurrentPage(1);
}
// no setter
public Map<Object, Boolean> getChecked() {
return checked;
}
public int getCurrentPage() {
return currentPage;
}
public boolean getSelectAll() {
return selectAll;
}
// no setter
public List<Object> getValuesOnPage() {
return valuesOnPage;
}
private void loadTable() {
try {
// gets data from data base
valuesOnPage = getData(currentPage);
} catch (Exception ex) {
System.out.println("Exception in loading table:" + ex);
}
}
public void setCurrentPage(int currentPage) {
if (this.currentPage != currentPage) {
this.currentPage = currentPage;
loadTable();
// we don't need it selected, especially if it
// was a paged we've never been on
selectAll = false;
}
}
public void setSelectAll(boolean selectAll) {
this.selectAll = selectAll;
for (Object o : valuesOnPage) {
checked.put(o, selectAll);
}
}
}
Look how and when the data is changing and when it is loaded. Check out that there's no unnessecary new action for checkbox of single row. JSF will take care of that with: value="#{bean.checked[data]}".
And once again: Your keys in map are objects. You have to make sure that equals method is good. In 95% of case the default is not, especially if they are #Entity. Check i.e. this topic.

Resources