Dynamic Column in JSF Datatable JSF2.0 - jsf

I need one help from you. I am using JSF 2.0 and I have a datatable component . One of the column in the datatable is an action column and I need to create a toolbar which contains different type of actionsource component such as command button, link etc. The type of actionsource is determined at run time and number of actionsource is also done at run time. How I can implement this in JSF 2.0
<p:dataTable value="#{listBranchBean1.rowDataModel}" var="rowItem"
id="myId" paginator="true"
paginatorTemplate="{FirstPageLink}{PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}{RowsPerPageDropdown} "
rowsPerPageTemplate="10,5,2" previousPageLinkLabel="<"
nextPageLinkLabel=">" widgetVar="branchTable"
selection="#{listBranchBean1.selectedBranchesPrime}"
resizableColumns="true"
sortBy="#{rowItem.columnsValueMap['branchId'].value}">
<f:facet name="header">
<p:outputPanel>
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="branchTable.filter()"
style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column selectionMode="multiple" style="text-align:left">
<f:facet name="header">
<h:outputText value="Select" />
</f:facet>
<h:outputText value="#{rowItem.uniqueId}" />
</p:column>
<p:column
rendered="#{listBranchBean1.columnsMap['objectId'].hidden==false}"
sortBy="#{rowItem.columnsValueMap['objectId'].value}"
filterBy="#{rowItem.columnsValueMap['objectId'].value}">
<f:facet name="header">
<h:outputText
value="#{listBranchBean1.columnsMap['objectId'].displayLabel}" />
</f:facet>
<h:outputText
value="#{rowItem.columnsValueMap['objectId'].value}" />
</p:column>
<p:column
rendered="#{listBranchBean1.columnsMap['actions'].hidden==false}">
<f:facet name="header">
<h:outputText
value="#{listBranchBean1.columnsMap['actions'].displayLabel}" />
</f:facet>
<p:toolbar>
<p:toolbarGroup>
<ui:repeat var="action"
value="#{rowItem.columnsValueMap['actions'].value}">
<p:commandButton title="#{action}" type="button">
</p:commandButton>
</ui:repeat>
</p:toolbarGroup>
</p:toolbar>
</p:column>
</p:dataTable>
I want to replace the last column with something like
<p:toolbar binding="#{listBranchBean1.getActions(rowItem)}">
</p:toolbar>
I appreciate your help
Prajeesh Nair

There is a difference between build-time and render-time in JSF. Build-time tags like <ui:repeat> have the ability to create new components dynamically, but they can only use data that is available at build-time.
However, using Java you are also allowed to alter the component tree programmatically, but this too can not just happen at any moment. The safe moment to do this is the preRenderViewEvent, which is a good bit later than the build-time moment (which is the restore view phase) and you should have all the data you need by then.
Inside an event handler for this event you can reference the tool bar you bound to your backing bean, and programmatically add columns to it.
For examples see:
http://balusc.omnifaces.org/2006/06/using-datatables.html#PopulateDynamicDatatable
http://arjan-tijms.omnifaces.org/2011/09/authoring-jsf-pages-in-pure-java.html
Do note that if your backing bean is #ViewScoped, you'd better not use binding but use a manual lookup instead. This is due to some bugs with respect to the view scope and binding components in JSF.

below code will create dynamic column on the basis of selected country
public void loadDynamicList() throws Exception {
int i=0;
dynamicList = new ArrayList<List<String>>();
dynamicList.add(Arrays.asList(new String[] { "ID1" }));
existingCountryList = new ArrayList<Country>();
String countryCode="US";
existingCountryList.add(getCountryService().getCountryByCode(countryCode));
Country country=getCountryService().getCountryByCode(countryCode);
countryLanguageSet=country.getCountryLanguage();
i=country.getCountryLanguage().size();
dynamicHeaders = new String[i] ;
int j=0;
for (CountryLanguage count: countryLanguageSet) {
System.out.println(count.getLanguage().getLanguageName());
dynamicHeaders[j]=count.getLanguage().getLanguageName();
j++;
}
}
public void populateDynamicDataTable() {
debugLogger.debug("populateDynamicDataTable:Enter");
// Create <h:dataTable value="#{myBean.dynamicList}" var="dynamicItem">.
HtmlDataTable dynamicDataTable = new HtmlDataTable();
dynamicDataTable.setValueExpression("value", createValueExpression("#{relationBean.dynamicList}", List.class));
dynamicDataTable.setVar("dynamicItem");
// Iterate over columns.
for (int i = 0; i < dynamicHeaders.length; i++) {
// Create <h:column>.
HtmlColumn column = new HtmlColumn();
dynamicDataTable.getChildren().add(column);
// Create <h:outputText value="dynamicHeaders[i]"> for <f:facet name="header"> of column.
HtmlOutputText header = new HtmlOutputText();
header.setValue(dynamicHeaders[i]);
column.setHeader(header);
HtmlInputText input=new HtmlInputText();
column.getChildren().add(input);
}
dynamicDataTableGroup = new HtmlPanelGroup();
dynamicDataTableGroup.getChildren().add(dynamicDataTable);
debugLogger.debug("populateDynamicDataTable:Exit");
}
public HtmlPanelGroup getDynamicDataTableGroup() throws Exception {
// This will be called once in the first RESTORE VIEW phase.
if (dynamicDataTableGroup == null) {
loadDynamicList(); // Preload dynamic list.
populateDynamicDataTable(); // Populate editable datatable.
}
return dynamicDataTableGroup;
}
public List<List<String>> getDynamicList() {
return dynamicList;
}
public void setDynamicList(List<List<String>> dynamicList) {
this.dynamicList = dynamicList;
}
public void setDynamicDataTableGroup(HtmlPanelGroup dynamicDataTableGroup) {
this.dynamicDataTableGroup = dynamicDataTableGroup;
}
public ValueExpression createValueExpression(String valueExpression, Class<?> valueType) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createValueExpression(
facesContext.getELContext(), valueExpression, valueType);
}

Related

Can't get filtering to work on PrimeFaces DataTable

I am trying to use filtering on my datatable. Whenever the table first loads, it looks like this:
If I enter text into the filter of user name, the table looks like this:
I would expect it to only show dangreen87 since mike.smith does not contain a "d". It however just displays no user names. Im not sure what this behaviour is?
I have a datatable like so:
<h:body>
<ui:composition>
<h:panelGroup layout="block" styleClass="messagesPanel" rendered="#{socialAdvertiserManagedBean.displaySearch}" >
<p:dataTable
resizableColumns="true"
var="account"
value="#{searchManagedBean.accountsToDisplay}"
scrollable="true"
paginator="true"
rows="10"
rowKey="#{account.id_value}"
emptyMessage="No accounts found for the given criteria"
widgetVar="searchTable"
filteredValue="#{searchManagedBean.filteredAccounts}">
<f:facet name="header">
#{searchManagedBean.isCompany ? 'Company' : 'Social Advertisers'}
</f:facet>
<p:column headerText="Image">
<p:graphicImage value="/dbimages/#{accountManagedBean.getImageId(account)}" width="25" height="25"/>
</p:column>
<c:if test="#{searchManagedBean.isCompany}" >
<p:column headerText="Company Name">
<h:outputLabel value="#{accountManagedBean.getCompany(account).name}" />
</p:column>
</c:if>
<c:if test="#{not searchManagedBean.isCompany}" >
<p:column id="userNameColumn" filterBy="#{account.userName}" filterMatchMode="contains">
<f:facet name="header">
<h:outputLabel value="User Name"/>
</f:facet>
<h:outputLabel value="#{account.userName}" />
</p:column>
</c:if>
</p:dataTable>
My Backing bean looks like so:
#ManagedBean
#ViewScoped
public class SearchManagedBean implements Serializable
{
private boolean isCompany;
private Account selectedAccount;
#EJB
private AccountDao accountDao;
#EJB
private SocialAdvertiserDao socialAdvertiserDao;
#EJB
private CompanyDao companyDao;
private List<Account> filteredAccounts;
#PostConstruct
public void init()
{
isCompany = true;
}
public List<Account> getAccountsToDisplay()
{
List temp;
if(isCompany)
{
temp = companyDao.findAll();
}
else
{
temp = socialAdvertiserDao.findAll();
}
return temp;
}
public List<Account> getFilteredAccounts() {
return filteredAccounts;
}
public void setFilteredAccounts(List<Account> filteredAccounts) {
this.filteredAccounts = filteredAccounts;
}
public boolean getIsCompany() {
return isCompany;
}
public void setIsCompany(boolean isCompany) {
this.isCompany = isCompany;
}
....
Those JSTL <c:if> tags bound to a view scoped bean property is the culprit.
<c:if test="#{not searchManagedBean.isCompany}" >
<p:column id="userNameColumn" filterBy="#{account.userName}" filterMatchMode="contains">
...
</p:column>
</c:if>
Long story short, carefully read #ViewScoped fails in taghandlers and JSTL in JSF2 Facelets... makes sense? In a nutshell, it causes the view scoped bean to be recreated on every single HTTP request and therefore a complete reset of the bean's state across the filtering and sorting ajax requests.
This #ViewScoped+taghandler issue is solved since Mojarra 2.1.18. Basically, you'd need to upgrade to at least Mojarra 2.1.18 (it's currently already at 2.1.25). However, this is after all not the canonical approach. You should just use the rendered attribute of <p:column> for that.
<p:column id="userNameColumn" filterBy="#{account.userName}" filterMatchMode="contains" rendered="#{not searchManagedBean.isCompany}">
...
</p:column>

Primefaces update table after on-cell editing

I have a data table with on-cell editing feature, and I want to update the data table to show the modified record by apply them a different style class.
Here are my problems:
If i do not update the data table when the onCellEdit event fires, records are correctly updated, but I cannot see the applyed style class for modified rows.
If I update the data table when the onCellEdit event fires and use the return key to update a value, all works fine, and I can see the applied style class for modified rows.
If I update the data table when the on-cell edit event fires and use the mouse clic to update a value (clicking on another row or on another cell within the same row), only the first value is updated correctly; when trying to update other values, the onCellEdit event triggers before I can insert the new value, so the event triggers with newValue=oldValue, for all the subsequent changes.
The xhtml page:
<h:form id="frm_tbl_riv">
<p:dataTable id="tbl_rilevazioni" var="rilevazione"
value="#{rilevazioni.rilevazioni}" widgetVar="tbl_rilevazioni_id"
editable="true" editMode="cell" scrollable="true" scrollHeight="350"
rowKey="#{rilevazione.idRilevazione}" selectionMode="single"
selection="#{rilevazioni.selezionata}">
<p:ajax event="rowSelect"
update=":tView:frm_tbl_riv:popup_rilevazioni" />
<p:ajax event="cellEdit" listener="#{rilevazioni.onCellEdit}"
update=":tView:frm_btn_riv" />
<!-- update=":frm_btn_riv :frm_tbl_riv" -->
<p:ajax event="contextMenu"
listener="#{rilevazioni.onRilevazioneSelezionata}"
update="#this" />
<p:column headerText="#{msg['rilevazione']}" width="130">
<f:facet name="header">
<h:outputText value="#{msg['rilevazione']}" />
</f:facet>
<h:outputText value="#{rilevazione.descRilevazione}" id="descRil" />
</p:column>
<p:column headerText="#{msg['valore']}"
styleClass="#{rilevazioni.isModificata(rilevazione) ? 'modificata' : ''}"
width="30">
<h:outputText value="#{rilevazione.valore}"
rendered="#{!rilevazioni.isModificabile(rilevazione)}" />
<p:cellEditor
rendered="#{rilevazioni.isModificabile(rilevazione)}">
<f:facet name="output">
<h:outputText value="#{rilevazione.valore}" />
</f:facet>
<f:facet name="input">
<p:inputText value="#{rilevazione.valore}"
label="#{msg['valore']}">
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
</h:form>
And the managed bean (view scoped):
#ManagedBean(name = "rilevazioni")
#ViewScoped
public class GestioneRilevazioniBean implements Serializable
{
// ...
public void onCellEdit(CellEditEvent event)
{
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage msg = null;
Object nuovoValore = event.getNewValue();
Object vecchioValore = event.getOldValue();
int i = event.getRowIndex();
RilevazioneGiornaliera r = rilevazioni.get(i);
r.setIdUtente(userBean.getUserId());
if (!nuovoValore.equals(vecchioValore))
{
try
{
RilevazioniService.getInstance().updateRilevazioneGiornaliera(r);
modificate.add(r);
} catch (Throwable ex)
{
// ...
}
}
}
public boolean isModificata(RilevazioneGiornaliera riv)
{
return modificate.contains(riv);
}
public boolean isModificabile(RilevazioneGiornaliera rilevazione)
{
// some logic
return true;
}
}
If I use:
update=":frm_btn_riv :frm_tbl_riv"
for the on-cell edit event, I obtain the behaviour specified on point 2 and 3. The same with #form or #parent.
I have founded a solution to update the style class to the modified cell after the onCellEdit event fires.
Data table:
<p:ajax event="cellEdit" listener="#{rilevazioni.onCellEdit}"
oncomplete="handleRilevazioniCellEdit(xhr, status, args);" />
// ...
// within the cell editor
<p:inputText id="rilevazioniCellEditInputtext" value="#{rilevazione.valore}"
label="#{msg['valore']}" />
Javascript:
<script>
function handleRilevazioniCellEdit(xhr, status, args)
{
var modelInput = $('#parentId:' + args.rowIndex + '\\:rilevazioniCellEditInputtext');
var cell = modelInput.parent().parent().parent();
cell.addClass('modificata');
}
</script>
Managed bean, at the end of the onCellEdit() event:
RequestContext requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("rowIndex", event.getRowIndex());

Request doesn't render response in primefaces datatable

I have a datatable with search field and commandLink to sort. The commandLink that I use to trigger sorting is located not in column header but on the header of datatable. When I load my page and use only commandLink to sort everything works ok. Table sorts in two orders and I see result on my page. Problem appears when I search something in globalFilter. It also works, but after that I cant sort my table. I clear inputText of globalFilter and I cant sort table. To sum up, I see result of sorting only when I not use search field. Sort operation works but request not update the datatable. I put my code below. Maybe somebody knows how to solve it.
<ui:composition>
<p:panel header="Moje pomiary" footer="#{msgs.footer}" id="myMeasurement">
<h:form id="form" prependId="false">
<p:dataTable var="m" value="#{myMeasurementTable.measurement}" id="measureList" editable="true"
widgetVar="mTable"
emptyMessage="No files found with given criteria" filteredValue="#{myMeasurementTable.filteredMeasurement}" >
<f:facet name="header">
Sortowanie według: <p:commandLink id="sortByName" actionListener="#{myMeasurementTable.sortByName}" update="measureList">
<h:outputText value="nazwa pliku" />
</p:commandLink>
|<h:commandLink action="#{myMeasurementTable.sortByArchivisationDate}"> data archiwizacji </h:commandLink>
|<h:commandLink action="#{myMeasurementTable.sortByMeasureDate}"> data badania </h:commandLink>
<p:outputPanel styleClass="searchPanel">
<h:outputText value="Szukaj: " />
<p:inputText styleClass="globalFilter" id="globalFilter" onkeyup="mTable.filter()" style="width:150px" />
</p:outputPanel>
</f:facet>
<p:column headerText="Informacje pomiarowe" style="width:125px" filterStyle="display:none" filterBy="#{m.fileName} #{m.measureDate} #{m.place} #{m.archivisationDate}"
filterMatchMode="contains" >
<p:separator styleClass="separatorColumn"/>
Nazwa pliku: <h:outputText value="#{m.fileName}" /><br />
Data badania: <h:outputText value="#{m.measureDate}" /><br />
Data archiwzacji: <h:outputText value="#{m.archivisationDate}" /><br />
Miejscowość: <h:outputText value="#{m.place}"/> <br />
Współrzędne GPS:
</p:column>
<p:column headerText="Wykresy">
<img src="/tmp/21/myfile.xls/myfile.xls_Parametr x.png" width="150"/>
</p:column> </p:dataTable></h:form></p:panel></ui:composition>
and part of my bean
#ManagedBean(name = "myMeasurementTable")
#ViewScoped
public class myMeasurementTable implements Serializable{
private static final long serialVersionUID = -9193902657201234669L;
private List<Measurement> measurement;
private List<Measurement> filteredMeasurement;
private boolean sortAscending = true;
public myMeasurementTable() {
measurement = new ArrayList<Measurement>();
fillTable(measurement);
}
public String sortByName() {
System.out.println("naciskam sortowanie");
if (sortAscending) {
Collections.sort(measurement, new Comparator<Measurement>() {
#Override
public int compare(Measurement m1, Measurement m2) {
return m1.getFileName().compareTo(m2.getFileName());
}
});
sortAscending = false;
} else {
Collections.sort(measurement, new Comparator<Measurement>() {
#Override
public int compare(Measurement m1, Measurement m2) {
System.out.println(m2.getFileName());
return m2.getFileName().compareTo(m1.getFileName());
}
});
sortAscending = true;
}
return null;
}
Ok I found solution on primefaces forum. It's simple. I only added oncomplete="mTable.filter()" to commandButton and everything works as I want.

How do I save an Object from selectOneMenu using Omnifaces Converter into a database?

I have a problem using a OmniFaces converter with primefaces selectOneMenu. I am displaying a list of Departments in a primefaces datatable with in-cell editing function, one column displays department name while the other displays faculty name.
When editing, the selectOneMenu shows correctly with a list of faculties to select from but won't get saved on submitting, when i remove the faculty column in datatable, the department name get saved without a problem, someone help me find out why i cant save faculty name.
Here are is my datatable code
<p:dataTable id="deptTable" var="department"
value="#{departmentMB.departmentList}" editable="true"
rowIndexVar="rowIndex">
<p:ajax event="rowEdit" listener="#{departmentView.onEdit}"
update=":deptForm:messages" />
<p:column headerText="Name">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{department.departmentName}" />
</f:facet>
<f:facet name="input">
<h:inputText value="#{department.departmentName}" />
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Faculty">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{department.faculty.facultyName}" />
</f:facet>
<f:facet name="input">
<p:selectOneMenu id="iterator"
value="#{departmentMB.selectedFaculty}"
converter="facultyConverter" label="Faculty">
<f:selectItem itemLabel="Select one" noSelectionOption="true" />
<f:selectItems value="#{facultyMB.facultyList}" var="faculty"
itemLabel="#{faculty.facultyName}" itemValue="#{faculty}" />
</p:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
here is department controller
#ManagedBean(name = "departmentMB")
#RequestScoped
public class DepartmentController implements Serializable {
#ManagedProperty(value = "#{DepartmentService}")
IDepartmentService departmentService;
private static final long serialVersionUID = 1L;
private int department_id;
private String departmentName;
private Faculty selectedFaculty;
.
.
.//getters and setters
Here is onEdit method
public void onEdit(RowEditEvent event) {
try {
Department department = (Department) event.getObject();
DepartmentController departmentController = (DepartmentController) FacesContext
.getCurrentInstance().getExternalContext().getRequestMap()
.get("departmentMB");
departmentController.updateDepartment(department);
} catch (Exception e) {
e.printStackTrace();
}
}
Here is the update method - uses hibernate save() method
public void updateDepartment(Department department) {
try {
getDepartmentService().updateDepartment(department);
} catch (DataAccessException e) {
e.printStackTrace();
}
}
And finally my OmniFaces Converter
#FacesConverter("facultyConverter")
public class FacultyConverter extends SelectItemsConverter {
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
Integer id = (value instanceof Faculty) ? ((Faculty) value).getFacultyId() : null;
return (id != null) ? String.valueOf(id) : null;
}
}
In the <p:selectOneMenu>, you need to set the selected faculty on the currently iterated row, not on the parent backing bean.
In other words, replace
<p:dataTable ... value="#{departmentMB.departmentList}" var="department">
...
<p:selectOneMenu ... value="#{departmentMB.selectedFaculty}">
by
<p:dataTable ... value="#{departmentMB.departmentList}" var="department">
...
<p:selectOneMenu ... value="#{department.faculty}">
This concrete problem is further unrelated to the converter. It is doing its job just fine.
Wrong question. JSF is a presentation framework, it does not handle storage/bussiness logic.
In your backing bean, the appropiate method should take care of storage, but it will ignore from where your bean comes. You can do manually (JDBC) or with an ORM framework (Hibernate, JPA)
And BTW, if your question is "Why the selected object is not stored in departmentMB.selectedFaculty?", your converter is not implementing getAsObject()

Using <h:selectBooleanCheckbox> with Map in a paginated <p:dataTable> throws NullPointerException

I am using PrimeFaces <p:dataTable> with pagination. I use <h:selectBooleancheckbox> with a Map property for corresponding row selection. The problem which I am facing is when I select and submit the values, there is a NullPointerException. The values are checked for particular rows only. I am using JSF 2.0 and PrimeFaces 3.0.
My page is:
<p:dataTable id="ngoPhotoTab" paginator="true" rows="10" value="# {photoApprovelBean.lstNgoPhotos}" var="ngoPhoto">
<p:column headerText="NgoName">
#{ngoPhoto.ngoName}
</p:column>
<p:column headerText="Select">
<h:selectBooleanCheckbox id="ngoSelect" layout="pageDirection" value="#{photoApprovelBean.checked[ngoPhoto.photo_id]}" />
</p:column>
<f:facet name="footer">
<p:commandButton onclick="deletePhoto();" value="Delete" />
</f:facet>
</p:dataTable>
Backing bean logic:
public class PhotoApprovelBean {
public String deleteActPhoto() {
List checkedItems = new ArrayList();
try {
for (Iterator<PhotoApprovelBean> itr = disAppPhotoList.iterator(); itr.hasNext();) {
PhotoApprovelBean item = (PhotoApprovelBean) itr.next();
if (checked.get(item.getPhotoId())) {
checkedItems.add(item.getPhotoId());
}
}
toDeletePhoto(checkedItems);
}catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
public Map<Long, Boolean> getChecked() {
return checked;
}
}
The NullPointerException is caused in the line if (checked.get(item.getPhotoId())). The The Map is filled with values of first page only. How is this caused and how can I solve it?
You got a NullPointerException, because the if statement expects a boolean, but the Map contains Boolean values only which can possibly be null. They will be null for other pages. The Boolean value of null can't be autoboxed to a boolean. You'd need to add a nullcheck.
Boolean itemChecked = checked.get(item.getPhotoId());
if (itemChecked != null && itemChecked) {
// ...
}
Better, however, is to use PrimeFaces own <p:column selectionMode="multiple"> instead. It will remember the selection on other pages. The Map approach is only suitable if you don't use pagination. See also the showcase example. Here's how it can look like for you:
<p:dataTable id="ngoPhotoTab" paginator="true" rows="10"
value="#{photoApprovelBean.lstNgoPhotos}" var="ngoPhoto"
selection="#{photoApprovelBean.selectedNgoPhotos}" rowKey="#{ngoPhoto.photoId}"
>
<p:column headerText="NgoName">
#{ngoPhoto.ngoName}
</p:column>
<p:column headerText="Select" selectionMode="multiple" />
<f:facet name="footer">
<p:commandButton onclick="deletePhoto();" value="Delete" />
</f:facet>
</p:dataTable>
with
private PhotoApprovelBean[] selectedNgoPhotos;

Resources