Primefaces DataTable CellEdit not updating outputLabel - primefaces

I've actually found quite a bit on this in various different forums, but none of them appear to have worked for me. My problem isn't even that complicated, but I can't figure out why it's not working. I've set up my datatable so that it's editable and set the editMode="cell". I set up the ajax event and it fires, but the new and old values are always null.
When I'm finished editing a cell and go to the next cell, the cell goes back to the old value. When I click back into it, it shows the new value. Both the outputLabel and inputText tags use the exact same variable, but they are not showing the same value. I've tried manually updating the table manually through the method call as well and that does nothing. Also tried putting a p:ajax tag inside the inputText tag to update the table and that didn't work either.
Here's my JSF code:
<p:dataTable id="dynamicTable" value="#{column.values}" var="value" editable="true" editMode="cell">
<p:ajax event="cellEdit" listener="bean.updateCell" immediate="true" update=":dynamicTable"/>
<p:columns value="#{bean.columns}" var="column">
<f:facet name="header">
<p:outputLabel value="#{column.name}"/>
</f:facet>
<p:cellEditor>
<f:facet name="output"><p:outputLabel value="#{value}"/></f:facet>
<f:facet name="input"><p:inputText value="#{value}"/></f:facet>
</p:cellEditor>
</p:columns>
</p:dataTable>
Here's my bean:
#ManagedBean(name = "bean")
#ViewScoped
public class Bean implements Serializable {
private ArrayList<Column> columns;
public ArrayList<Column> getColumns(){
return columns;
}
public void setColumns(ArrayList<Column> columns){
this.columns = columns;
}
#PostConstruct
void init(){
columns = new ArrayList<>();
Column column = new Column();
column.setName("Acronym");
ArrayList<String> values = new ArrayList<>();
values.add("KFC");
values.add("TTYL");
values.add("BRB");
column.setValues(values);
columns.add(column);
column = new Column();
column.setName("Meaning");
values = new ArrayList<>();
values.add("Kentuky Fried Chicken");
values.add("Talk to you later");
values.add("Be right back");
column.setValues(values);
columns.add(column);
}
public void updateCell(CellEditEvent event){
System.out.println((String) event.getNewValue();
}
}
And my Column class:
public class Column{
private ArrayList<String> values;
private String name;
public ArrayList<String> getValues(){
return values;
}
public void setValues(ArrayList<String> values){
this.values = values;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
I rewrote the code to not include sensitive information and renamed variables, so if I'm missing something it's possible that I already have it in my code, but have accidentally removed it.

It turns out the way I was doing the p:columns tag was incorrect. After I made the following changes my problem was solved.
I've made an additional class called TableRow with various String objects to signify the columns to be used. Here's the new code:
JSF:
<p:dataTable id="dynamicTable" value="#{bean.tblRows}" var="row" editable="true" editMode="cell">
<p:columns value="#{bean.columns}" var="column">
<f:facet name="header">
<p:outputLabel value="#{column.name}"/>
</f:facet>
<p:cellEditor>
<f:facet name="output"><p:outputLabel value="#{row[column.variable]}"/></f:facet>
<f:facet name="output"><p:inputText value="#{row[column.variable]}"/></f:facet>
</p:cellEditor>
</p:columns>
</p:dataTable>
Bean:
#ManagedBean (name = "bean")
#ViewScoped
public class Bean implements Serializable {
private ArrayList<TableRow> tblRows;
private ArrayList<Column> columns;
public ArrayList<TableRow> getTblRows(){
return tblRows;
}
public void setTblRows(ArrayList<TableRow> tblRows){
this.tblRows = tblRows;
}
public ArrayList<Column> getColumns(){
return columns;
}
public void setColumns(ArrayList<Column> columns){
this.columns = columns;
}
#PostConstruct
void init(){
columns = new ArrayList<>();
columns.add(new Column("Acronym", "col1");
columns.add(new Column("Meaning", "col2");
tblRows = new ArrayList<>();
tblRows.add(new TableRow("KFC", "Kentuky Fried Chicken"));
tblRows.add(new TableRow("TTYL", "Talk to you later"));
tblRows.add(new TableRow("BRB", "Be right back"));
}
}
TableRow Class:
public class TableRow {
private String col1;
private String col2;
public TableRow(String col1, String col2){
this.col1 = col1;
this.col2 = col2;
}
public String getCol1(){
return col1;
}
public void setCol1(String col1){
this.col1 = col1;
}
public String getCol2(){
return col2;
}
public void setCol2(String col2){
this.col2 = col2;
}
}
Column Class:
public class Column {
private String name;
private String variable;
public Column(String name, String variable){
this.name = name;
this.variable = variable;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public String getVariable(){
return variable;
}
public void setVariable(String variable){
this.variable = variable;
}
}
The reason why I did "col1" and "col2" instead of give distinct variable names is that the user can choose the column header names so I won't know what to name the variables ahead of time. I was wondering if anyone would like to enlighten me how I could handle this dynamically a little better. When the bean is initialized I don't know how many columns there are going to be or what the column names are going to be.

Related

How to filter a dynamic datatable in primefaces? It is not working

I have created a dynamic datatable in primefaces and tried to filter the columns but the filter is not working, help me please.
I have created a table where columns headers and values that is properties are rendered dynamically and iterated by the var of a datatable.
primefaces code below
<p:dataTable var="sales" value="#{customermisreportbean.custList}"
paginator="#{customermisreportbean.pagenatorActive}" rows="#{customermisreportbean.pagenatorActive?10:0}"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="5,10,15" id="misreport" lazy="true"
filteredValue="#{customermisreportbean.filterval}" widgetVar="mistable">
<p:columns value="#{customermisreportbean.reportcolumns}"
var="column" filterBy="#{sales[column.property]}" columnIndexVar="colindex" headerText="#{column.header}">
<h:outputText value="#{sales[column.property]}"
styleClass="#{column.align}" />
</p:columns>
</p:dataTable>
Below is the bean class
public class columns implements Serializable{
private String header="";
private String property="";
private String align="";
public columns(String header, String property,String align) {
this.header = header;
this.property = property;
this.align=align;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
public String getAlign() {
return align;
}
public void setAlign(String align) {
this.align = align;
}
}

Primefaces selectOneListbox not displaying item text (nor is the data contained in the items)

My PrimeFaces selectOneListbox has 3000 items in it - as can be seen from the object inspector in chrome's debugger. The div rows are all there, but there's no data in them for display text. The divs are all empty.
I double checked and the itemValue points to the company.name which has data in it. Also, the itemLabel gets the unique symbol for the company, so that should be fine too, because that data is all valid. However, I've missed something because the UI shows a blank box and is visibly taller than its empty default - and as I said, contains the 3000 empty items in the form of empty divs in chrome's debugger.
The code in my xhtml for the selectOneListbox is the following. I've tried a map as a collection and a list in my managed bean (so I changed the value to whichever variable I wanted to try). Both the map and the list of companies yielded the same results - a list of 3000 entries in the javascript (shown below)
<p:selectOneListbox id="symbolPicker" value="#{simulationBean.company}" converter="companyConverter" var="t" filter="true" filterMatchMode="contains">
<f:selectItems value="#{simulationBean.companyMap}" var="company" itemLabel="#{company.symbol}" itemValue="#{company}" />
</p:selectOneListbox>
The javascript of the empty items:
The managed bean just stores a list of companies that are all obviously initialized #PostConstruct, because the objects are being enumerated (3000 of them) in my debugger - so the companies are there and their data is valid (I can see the data in the debugger).
And I'm guessing the culprit will be in this next object. I can't imagine what I'm missing - it seems it must be really obvious - here's the company entity itself:
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.google.gson.JsonObject;
#Entity
#Table(name = "company")
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
private String symbol;
#Column
private String name;
#Column(columnDefinition="market_category")
private String marketCategory;
#Column(columnDefinition="test_issue")
private Integer testIssue;
#Column(columnDefinition="good_status")
private Integer goodStatus;
#Column(columnDefinition="round_lot")
private Integer roundLot;
#Column
private Integer etf;
public Company() {}
public Company(String symbol, String name, String marketCategory, Integer testIssue, Integer goodStatus, Integer roundLot, Integer etf) {
super();
this.symbol = symbol;
this.name = name;
this.marketCategory = marketCategory;
this.testIssue = testIssue;
this.goodStatus = goodStatus;
this.roundLot = roundLot;
this.etf = etf;
}
#Id
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMarketCategory() {
return marketCategory;
}
public void setMarketCategory(String marketCategory) {
this.marketCategory = marketCategory;
}
public Integer getTestIssue() {
return testIssue;
}
public void setTestIssue(Integer testIssue) {
this.testIssue = testIssue;
}
public Integer getGoodStatus() {
return goodStatus;
}
public void setGoodStatus(Integer goodStatus) {
this.goodStatus = goodStatus;
}
public Integer getRoundLot() {
return roundLot;
}
public void setRoundLot(Integer roundLot) {
this.roundLot = roundLot;
}
public Integer getEtf() {
return etf;
}
public void setEtf(Integer etf) {
this.etf = etf;
}
#Override
public String toString() {
return symbol;
}
public String toDebugString() {
return "Company [symbol=" + symbol + ", name=" + name + ", marketCategory=" + marketCategory + ", testIssue="
+ testIssue + ", goodStatus=" + goodStatus + ", roundLot=" + roundLot + ", etf=" + etf + "]";
}
#Transient
public JsonObject getJsonObject() {
JsonObject result = new JsonObject();
result.addProperty("symbol", symbol);
result.addProperty("name", name);
result.addProperty("marketCategory", marketCategory);
result.addProperty("testIssue", testIssue);
result.addProperty("goodStatus", goodStatus);
result.addProperty("roundLot", roundLot);
result.addProperty("etf", etf);
return result;
}
#Override
public boolean equals(Object obj) {
// null check
if (obj == null) {
return false;
}
// this instance check
if (this == obj) {
return true;
}
// instanceof Check and actual value check
if ((obj instanceof Company) && (((Company) obj).getSymbol() == this.symbol)) {
return true;
} else {
return false;
}
}
#Override
public int hashCode() {
return symbol.hashCode();
}
}
And now I have a converter as well:
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import com.appzany.stockService.BeanUtil;
import com.appzany.stockService.entity.Company;
import com.appzany.stockService.stockservice.StockService;
#FacesConverter("companyConverter")
public class CompanyConverter implements Converter {
private StockService stockService = null;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(stockService == null)
stockService = BeanUtil.getBean(StockService.class);
return stockService.getCompany(value);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Company)value).getSymbol();
}
}
You seem to be wanting to use the 'Advanced' p:selectOneListbox which in their showcase is as follows
<p:selectOneListbox id="advanced" value="#{selectOneView.theme}" converter="themeConverter" var="t" filter="true" filterMatchMode="contains">
<f:selectItems value="#{selectOneView.themes}" var="theme" itemLabel="#{theme.displayName}" itemValue="#{theme}" />
<p:column>
<h:graphicImage name="showcase/images/themeswitcher/themeswitcher-#{t.name}.png" alt="#{t.name}" styleClass="ui-theme" />
</p:column>
<p:column>
<h:outputText value="#{t.displayName}" />
</p:column>
</p:selectOneListbox>
Where both the p:selectOneListbox and the f:selectItems have a var attribute of which the var attribute of the p:selectOneListbox is being used in explicit additional tags inside this component. These additional p:column tags and their content take care of the 'advanced' rendering. You don't have any of this, which I think (sorry, did not try) results in rendering 'nothing'. If you'd add something to render like
<p:column>
<h:outputText value="#{t.name}" />
</p:column>
<p:column>
<h:outputText value="#{t.symbol}" />
</p:column>
I'm sure something IS rendered.

Refreshing model data on tab change event

I'm using primefaces tabView component. Each tag has its own managed bean and .xhtml page referencing that bean.
The problem is that EACH TIME tab is clicked, fresh data should be fetched from database (not just the first time), in other words data should be refreshed.
My beans are #ViewScoped. I don't want to use #RequestScoped because I have very dynamic ajax-enabled pages.
My solution currently looks like this:
I have managed bean for the main page with tabView component (MainBean) which contains method for handling tabChange event.
That bean also has references to beans assigned to each tab (TabBean1, TabBean2) so that right bean could be refreshed according to the id of the chosen tab.
MainBean:
#ManagedBean(name = "mainBean")
#ViewScoped
public class MainBean implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty(value = "#{tabBean1}")
private TabBean1 tabBean1;
#ManagedProperty(value = "#{tabBean2}")
private TabBean2 tabBean2;
public void onTabChange(TabChangeEvent event) {
String id = event.getTab().getId();
if ("tab1Id".equals(id)) {
tabBean1.init();
} else if ("tab2Id".equals(id)) {
tabBean2.init();
}
}
public TabBean1 getTabBean1() {
return tabBean1;
}
public void setTabBean1(TabBean1 tabBean1) {
this.tabBean1 = tabBean1;
}
public TabBean2 getTabBean2() {
return tabBean2;
}
public void setTabBean2(TabBean2 tabBean2) {
this.tabBean2 = tabBean2;
}
}
TabBean1:
#ManagedBean(name = "tabBean1")
#ViewScoped
public class TabBean1 implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> data;
#PostConstruct
public void init() {
// refresh data
}
}
TabBean2:
#ManagedBean(name = "tabBean2")
#ViewScoped
public class TabBean2 implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> data;
#PostConstruct
public void init() {
// refresh data
}
}
Relevant part od main.xhtml:
<p:tabView id="tabViewID" cache="false" dynamic="true">
<p:ajax event="tabChange" listener="#{mainBean.onTabChange}" />
<p:tab title="Tab 1" id="tab1Id">
<ui:include src="tab1Page.xhtml" />
</p:tab>
<p:tab title="Tab 2" id="tab2Id">
<ui:include src="tab2Page.xhtml" />
</p:tab>
</p:tabView>
Problem with this approach is:
when MainBean is constructed, all its managed properties are constructed also. This is a huge problem because #PostConstruct method of each bean fetches some data from database and everything is just too slow beacuse all beans are initialized when only one should really be initialized (the one assigned to selected tab)
on first page load, init() method is called twice for TabBean1, once because of #PostConstruct and once because it is assigned to tabChange event (first tab is selected by default)
My question is:
how can I 'refresh bean data' when corresponding tab is clicked?
how can I do that dynamically, just for the chosen tab (initially and every click after)?
I would really appreciate your suggestions. Thanks!
I'm using Primefaces 6.0, JSF 2.2.

OrderList component works until submit the page

I have a page with an orderList component that is working partially.
This is the orderList
It has a list of names and also hold the ID for each system.
<p:orderList id="orderListAppList" value="#{manageApplications.listOfApplicationsAndIds}" var="app" controlsLocation="none" itemLabel="#{app.applicationName}" itemValue="#{app.applicationId}" >
<p:ajax event="select" listener="#{manageApplications.onSelect}"/>
<p:ajax event="unselect" listener="#{manageApplications.onUnselect}"/>
</p:orderList>
This is working as expected until I have added a button on the page that execute with ajax=false
When I click on this new button the error below is being thrown
javax.el.PropertyNotFoundException: Property 'applicationId' not found on type java.lang.String
This is the code that load the ArrayList used in the orderList component
#ManagedBean
#ViewScoped
public class ManageApplications implements Serializable {
private List<ApplicationNameAndId> listOfApplicationsAndIds = new ArrayList<ApplicationNameAndId>();
#PostConstruct
public void init() {
populateApplications();
}
private void populateApplications() {
// HERE I LOAD THE APPLICATION'S LIST FROM THE DATABASE
listOfApplicationsAndIds = manageDbApplications.getApplicationsListFromDatabase();
}
// GETTERS AND SETTERS
public List<ApplicationNameAndId> getListOfApplicationsAndIds() {
return listOfApplicationsAndIds;
}
public void setListOfApplicationsAndIds(List<ApplicationNameAndId> listOfApplicationsAndIds) {
this.listOfApplicationsAndIds = listOfApplicationsAndIds;
}
}
This is the type ApplicationNameAndId
public class ApplicationNameAndId implements Serializable {
private static final long serialVersionUID = -2031225157408650765L;
String applicationId;
String applicationName;
public ApplicationNameAndId() {
}
public ApplicationNameAndId(String appName, String appId) {
this.applicationId = appId;
this.applicationName = appName;
}
// GETTERS AND SETTERS
public String getApplicationId() {
return applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
}
My point is.
The component is working normally until I use some button with ajax=false.
<p:commandButton actionListener="#{manageApplications.selectQueuesToAddToAnExistingApplication(qmgr.queueManagerNameId)}"
oncomplete="PF('dlgAddQueuesToApplication').show();"
update=":j_idt3:addQueuesToApplicationPanel"
value="ADD QUEUE" ajax=false icon="fa fa-plus">
</p:commandButton>
Note that the "button" that I am talking about has nothing do to with the oederList component. Just adding a button that execute a listener (or something) with ajax=fase generate this error.
Any idea why?
The issue was related to the object that I was using.
The Application on my application's list is a Class that can be represented this way:
public class ApplicationNameAndId {
String applicationId;
String applicationName;
// CONSTRUCTOR
// GETTERS AND SETTERS HERE
}
The orderList component does not deal with your own object type, this expect to receive a List of Strings instead.
List<String> ListOfStringToBeUsed
For now I have adapted my code to return the list of Strings as expected.
When having more time I will create a custom converter class (to use my own object type) than post the how to here.
I hope this helps someone else,
Neliosam

PrimeFaces SelectOneRadio

I have one req , where I have a datable , which has x columns. One column contains 3 radio buttons .Which i am able to display . But my problem is I want one radio button to be selected by default .
What I am doing : On Load of datatable i am creating one variable (also i tried with SlectIte list) , but unable to get checked value.
Can anyone provide a simple working example?
This is my demonstration which present how to default radio value in datatable
XHTML
<h:form>
<p:dataTable var="catalog" value="#{radioView.catalogs}">
<p:column headerText="City">
<p:selectOneRadio id="city"
value="#{catalog.city}"
columns="3">
<f:selectItems value="#{radioView.cities}"
var="c"
itemLabel="#{city}"
itemValue="#{city}"/>
</p:selectOneRadio>
</p:column>
</p:dataTable>
<p:commandButton value="changeSelection"
process="#form"
update="#form"
actionListener="#{radioView.changeSelection}"/>
<p:commandButton value="submit"
process="#form"
update="#form"
actionListener="#{radioView.submit}"/>
</h:form>
ManagedBean
#ManagedBean
public class RadioView {
private List<Catalog> catalogs;
private List<String> cities;
#PostConstruct
public void init() {
cities = new ArrayList<String>();
cities.add("San Francisco");
cities.add("London");
cities.add("Paris");
//default radio value
Catalog c1 = new Catalog("San Francisco");
Catalog c2 = new Catalog("London");
Catalog c3 = new Catalog("Paris");
Catalog c4 = new Catalog("London");
catalogs = new ArrayList<Catalog>();
catalogs.add(c1);
catalogs.add(c2);
catalogs.add(c3);
catalogs.add(c4);
}
public List<Catalog> getCatalogs() {
return catalogs;
}
public void setCatalogs(List<Catalog> catalogs) {
this.catalogs = catalogs;
}
public List<String> getCities() {
return cities;
}
public void changeSelection(ActionEvent event){
for (Catalog catalog : catalogs) {
catalog.setCity("San Francisco");
}
}
public void submit(ActionEvent event) {
for (Catalog catalog : catalogs) {
System.out.println(catalog.getCity());
}
}
}
Domain
public class Catalog implements Serializable{
private String city;
public Catalog(String city){
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}