Implement LazyDataModel in p:dataTable - jsf-2

I'm trying to implement a table with lazy loading. I think I got all steps from demo page and documentation but I always get a "No records found" message. I think I've reduced code to minimun expression, at least there should be one record :
Tables page:
<h:form id="listaEmpresas">
<p:dataTable id="tablaEmpresas" value="#{empresasTableMB.lazyDataModel}" var="empresa">
<p:column>
<f:facet name="header">
<h:outputText value="#{msgs.empresa_tabla_nombre}"/>
</f:facet>
<h:outputText value="#{empresa.nombre} "/>
</p:column>
</p:dataTable>
</h:form>
LazyDataModel:
#Override
public List<Empresa> load(int first, int pageSize, String sortField, SortOrder so, Map<String, String> filters) {
List<Empresa> listaEmpresas = new ArrayList();
Empresa e = new Empresa();
e.setNombre("Company");
listaEmpresas.add(e);
this.setRowCount(1);
return listaEmpresas;
}
#Override
public void setRowIndex(int rowIndex) {
if (rowIndex == -1 || getPageSize() == 0) {
super.setRowIndex(-1);
}
else
super.setRowIndex(rowIndex % getPageSize());
}
I must override setRowIndex or I get an exception "java.lang.ArithmeticException: / by zero". I'm using primefaces-3.1-SNAPSHOT, jsf 2.0.3, and tomcat 6.0. Please help. What I´m missing?

Add lazy=true in your dataTable.
After adding this datatable is able to call your load() method.

you need to add field private int rowCount;
and then in your load(...) method set value of number of record in your list to this field (rowCount).
without this thing <p:dataTable ...> will gain "No record found" and also if you don't specify rows ="10" (for example) attribute it will not render rows!

You need to implement LazyDataModel#getRowKey and LazyDataModel#getRowData as well.
Suppose that you have something like:
class Empresa {
private long id;
private String nombre;
// getters and setters...
}
Then:
getRowKey returns the id for an Empresa object
getRowData gets an Empresa object by id
class MyLazyDataModel {
// stuff you already have comes here...
public Empresa getRowData(String rowKey) {
return empresaRepository.getEmpresaById(Long.valueOf(rowKey));
}
public Object getRowKey(Empresa empresa) {
return empresa.getId();
}
}

This behavior is described in https://code.google.com/p/primefaces/issues/detail?id=1544 and apparently you can avoid it by explicitly calling lazyDataModel.setPageSize();
There is a related post here:
Primefaces DataTable + JPA / Hibernate Pagination

you are not calling the load method.first call the load method before the prime face data table declaration.

Related

PrimeFaces inputText enable/disable

I have two radio buttons on JSF2/PrimeFaces page, which I need to enable/disable an inputText field depending on the choice.
<h:form prependId="false">
<p:panelGrid id="notif">
<p:row id="notif1">
<p:column>
<h:outputText value="label" />
</p:column>
<p:column>
<p:selectOneRadio id="radiobuttons" value="#{state.radioStatus}" layout="pageDirection">
<f:selectItem itemLabel="enable" itemValue="enable" />
<f:selectItem itemLabel="disable" itemValue="disable" />
<p:ajax update="date" />
</p:selectOneRadio>
</p:column>
<p:column>
<p:inputText id="date" value="#{state.infoDate}" disabled="#{!state.checkStatus}" >
</p:inputText>
<p:inputText id="test" value="#{state.infoDateTest}">
</p:inputText>
</p:column>
</p:row>
</p:panelGrid>
</h:form>
Also this all is inside a tab, but there is no nested forms when checked the generated html. The fields seem to get the id of the tab, but they seem to be correct like this (Did not work when tried to use id notation 'tabView:date' for the ajax.)
The problem is that when entering the page, the 'actual' text field is disabled by default and should be enabled when the radio button is set to enable it. When the radio button status is updated, I can see the event is registered on the server side and the inputText field gets "visually" enabled (by default it is disabled as supposed to). However the field is not "focusable" after enabling it, so can't write to it.
The more bizarre it gets when I added the 'test' inputText field, which does not get it self enabled/disabled regarding to radio buttons. On a fresh page load you can write to it, but after changing the radio button status, it is not writable anymore (the text that was entered prior to ajax call, will remain, but is not editable).
However the radio buttons continue to work and will fire events on the server side.
Could someone point out what I may be doing incorrectly, or could this be a bug with PrimeFaces?
// Update
Like said, the managed bean works as supposed to, so I don't see any problems there, but here is the code (simplified and renamed for readability as the relevant parts are taken from a bigger context).
#ManagedBean(name = "state")
#SessionScoped
public class ExampleBean implements Serializable {
private static final String disable = "disable";
private static final String enable = "enable";
private String text;
private List<TestRow> rows = null;
private TestRow row = null;
private String radioStatus = "enable";
private String infoDate = "";
private String infoDateTest = "";
#PostConstruct
public void initEmpty() {
}
public String getRadioStatus() {
return this.radioStatus;
}
public void setRadioStatus(String radioStatus) {
this.radioStatus = radioStatus;
}
public String getInfoDate() {
return infoDate;
}
public void setInfoDate(String infoDate) {
this.infoDate = infoDate;
}
public String getInfoDateTest() {
return infoDateTest;
}
public void setInfoDateTest(String infoDateTest) {
this.infoDateTest = infoDateTest;
}
public boolean isCheckStatus() {
return this.radioStatus.equalsIgnoreCase(enable) ? true : false;
}
}
Unfortunately I was not able to figure out what is causing the actual problem. The basic thing seems to be that the inherited javascript (primefaces) is not working properly on this page (maybe because of some other js inherited). Finally I just made it a custom enable/disable js-function:
js.toggleDisableStatus = function(elementId) {
// Can't use jQuery $("#xx:yy"), the syntax is not accepted by jquery but
// used by JSF/PrimeFaces
var element = document.getElementById(elementId);
var attrValue = element.getAttribute('disabled');
if (attrValue === undefined || attrValue == null) {
element.disabled = true;
element.style.background = "#dddddd";
} else {
element.removeAttribute('disabled');
element.style.background = "";
}
};
This may be flawed but works for now. The radio buttons are selected by the persisted status (loaded in state) and the enable/disable state for the input-field is also set when initially loading the page. Generally I think this should work for this particular case.

composite component button action issue in jsf2 mojarra

Trying to develop a composite component using jsf2.0 (Mojarra) which should render command buttons dynamically based on the list from the bean. I was able to render the buttons but action is not getting triggered.Could any one please help me to resolve the issue?
Here follows the code
<composite:interface>
<composite:attribute name="buttonList" required="true"
type="java.util.List" />
<composite:attribute name="beanName" required="true"
type="java.lang.Object" />
</composite:interface>
<composite:implementation>
<ui:repeat var="listItem" value="#{cc.attrs.buttonList}">
<h:commandButton value="#{listItem.buttonName}"
action="#{cc.attrs.beanName.listItem.buttonAction}">
</h:commandButton>
</ui:repeat>
</composite:implementation>
This is used as
<utils:buttonGroup buttonList="#{testButtonBean.buttonList}"
beanName="#{testButtonBean}" />
The bean looks like
public class TestButtonBean {
public List<ButtonPOJO> buttonList = new ArrayList<ButtonPOJO>();
public List<ButtonPOJO> getButtonList() {
return buttonList;
}
public void setButtonList(List<ButtonPOJO> buttonList) {
this.buttonList = buttonList;
}
public void preProcess() {
if (null != buttonList && buttonList.size() == 0) {
ButtonPOJO ob1 = new ButtonPOJO("Continue", "next");
ButtonPOJO ob2 = new ButtonPOJO("Back", "prev");
buttonList.add(ob1);
buttonList.add(ob2);
}
}
public String next() {
return "page1";
}
public String prev() {
return "page2";
}
}
action="#{cc.attrs.beanName.listItem.buttonAction}"
This is not right. This syntax is basically looking for a property listItem on beanName and then trying to invoke the literal action buttonAction() on it.
You need the brace notation action="#{bean[methodName]}" if you want to specify the action method name as string coming from another bean property.
action="#{cc.attrs.beanName[listItem.buttonAction]}"
Unrelated to the concrete problem, if the above solution still fails, then that can only mean that the value="#{cc.attrs.buttonList}" has incompatibly changed during the form submit request. You need to make sure that exactly the same list is prepared during the postback as it was during the initial request. See also point 4 of commandButton/commandLink/ajax action/listener method not invoked or input value not updated.

Primefaces Datalist Pagination

I'm using a datalist with Ajax pagination and the first page loads fine, showing 5 results. It knows I've got 3 pages worth of results, but when I click through to the second/third pages, I get an empty list.
My model extends LazyDataModel and the first time my page loads, I can set a breakpoint on the load() method and I can see it's asking for results 1-5 which is great. But clicking on 'page 2' doesn't result in another call to the load method (although it does result in about 3 calls to my lazyDataModel field itself (just not the load method inside it).
New to this and despite reading a lot and trying out various things, I can't understand quite how it should work. The showcase example doesn't seem quite 'complete' to me.
Here's the most relevant bits of my code (I think). Sorry about the formatting:
#PostConstruct
public void LoadData() {
lazyModel = new LazyDataModel<MessageboardThread>() {
#Override
public List<MessageboardThread> load(int first, int pageSize, String sortField, SortOrder so, Map<String, String> map) {
List<MessageboardThread> result = new ArrayList<MessageboardThread>();
try {
result = mbDao.findAll(pageSize, first);
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
};
getLazyModel().setRowCount(mbDao.count());
getLazyModel().setPageSize(pageSize);
}
This method DOES get executed every time I click on next/prev page
/**
* #return the lazyModel
*/
public LazyDataModel getLazyModel() {
return lazyModel;
}
And this is my xhtml file
<p:dataList value="#{messageboardBean.lazyModel}" var="thread" id="threads"
paginator="true" rows="5" effectSpeed="fast"
paginatorTemplate="{PreviousPageLink} {CurrentPageReport} {NextPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" type="none"
paginatorPosition="bottom">
<f:facet name="header">
Conversations
</f:facet>
<p:column>
<h:outputText value="#{thread.title}" style="margin-left:10px" />
<br />
</p:column>
</p:dataList>
I'm stumped so really grateful for any help
PS I put a #PostContruct annotation there because it seemed to be a good place to do the setup but it could be wrong, I haven't seen it on any other examples, but then I couldn't get any other examples to work either.
Solved it. I forgot to wrap the dataList attribute in an h:form tag. It works fine now.

How to pass JSF variable to jQuery

Suppose i have JSF page
<h:body>
<h:form id="formID" prependId="false">
<h:outputText id="randomID" value="#{randomNumber.random}"/>
<h:commandButton id="buttonID"
value="Random"
onclick="myArrayList(countries)" /> //just example
</h:form>
</h:body>
#ViewScoped
public class RandomNumber {
private int totalCountries;
private String data = "Afghanistan, Albania, Zimbabwe";
private List<String> countries;
public RandomNumber() {
countries = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(data, ",");
while(st.hasMoreTokens()) {
countries.add(st.nextToken().trim());
}
totalCountries = countries.size();
} //end of constructor
} //end of class RandomNumber
.js file
function myArrayList(countries) {
.....
}
See when user click on button then i want to call Jquery function whom i am passing my ArrayList. Is it possible to pass your current JSF variable with values to javascript or jQuery?
Thanks
EDIT
**_________________________________________________-*
<h:body>
<h:form id="formID" prependId="false">
<h:outputText id="countries" value="#{countries.countries}" style="display:none"/>
<h:inputHidden id="hiddenCountries" value="#{countries.countries}" />
<h:commandButton id="buttonID"
value="Random"
onclick="myArrayList()"/>
</h:form>
</h:body>
#ViewScoped
public class Countries {
private int totalCountries;
private String data = "Afghanistan, Albania, Zimbabwe";
private List<String> countries;
/** Creates a new instance of Countries */
public Countries() {
countries = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(data, ",");
while(st.hasMoreTokens()) {
countries.add(st.nextToken().trim());
}
totalCountries = countries.size();
} //end of constructor
public List<String> getCountries() {
return countries;
}
public void setCountries(List<String> countries) {
this.countries = countries;
}
} //end of class Countries
function myArrayList() {
alert(jQuery('#countries').html());
alert(jQuery('#hiddenCountries').val()) //when using h:inputHidden
} //end of function myArrayList
You can do
<h:inputHidden id="someID" value="#{randomNumber.data}/>
(dont forget to added getter/setter to your data in the bean )
change your onclick of the h:commandButton
onclick="myArrayList()" // or onclick="myArrayList(#{SomeELExpressioGoesHere})"
change your js function into
function myArrayList(inputParam) {
alert(jQuery('#someID').val());
var yourJSString = jQuery('#someID').val();
var myArray = yourJSString.split(','); //when string is Afghanistan,Albania,Zimbabwe (no spaces)
alert(myArray[inputParam]);
}
in order to transfer your js string into array just use
var yourJSString = jQuery('#someID').val()
var myArray = yourJSString.split(','); //when string is Afghanistan,Albania,Zimbabwe (no spaces)
you might be needed to change someID into other id selector if you wont set prependId=false in your form... or simply use a broaded jquery selector like
alert(('input[id$="someID"]').val());
EDIT
Look at my example , you should work with your String data variable and not the countries , cause you should pass the data as string only and not as array... after you will pass the data variable to js you can manipulate it with simple slpit js function to make it back an array in your js... you are getting Conversion Error setting value '[Afghanistan, Albania, Zimbabwe]' for 'null cause you are trying to set String into array... probably the getter of countries converted implicitly the java array into string and when you try to submit it back (string into array) you getting the exception
in order to set from js back to to bean :
jQuery('#someID').val("Some new String goes here");
then when you will submit the form.. the value will be set back to server

h:selectoneradio validation error [duplicate]

This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 6 years ago.
Please, help me to tackle with next matter.
I have error "requestAccess:selectAccess: Validation Error: Value is not valid" when submit form.
<h:form id="requestAccess">
<h:selectOneMenu id="orgList" value="#{requestAccessBean.currentOrg}">
<f:selectItem itemLabel="-- select --" itemValue="null" />
<f:selectItems value="#{requestAccessBean.orgList}" />
<f:ajax event="change" execute="#this" render="selectAccess"/>
</h:selectOneMenu>
<h:selectOneRadio id="selectAccess" valueChangeListener="# {requestAccessBean.accessChanged}" value="#{requestAccessBean.currentAccess}" layout="pageDirection">
<f:selectItems value="#{requestAccessBean.accessList}" />
</h:selectOneRadio>
</h:form>
#ManagedBean(name = "requestAccessBean")
public class RequestAccessSection {
private List<SelectItem> accessList;
private List<SelectItem> orgList;
private String currentOrg,currentAccess;
public void accessChanged(ValueChangeEvent event) {
this.currentAccess = event.getNewValue();
}
public List<SelectItem> getAccessList() {
if (this.accessList == null) {
this.accessList = returnAccessList();
}
return this.accessList;
}
public List<SelectItem> getOrgList() {
if (this.orgList == null) {
this.orgList = returnOrgList();
}
return this.orgList;
}
public List<SelectItem> returnOrgList() {
List<OrgUnit> orgList = new ArrayList<OrgUnit>();
List<SelectItem> selectItemsOrgList = new ArrayList<SelectItem>();
orgList = getBusinessDelegate().getOfficeBranches();
for(OrgUnit org : orgList){
selectItemsOrgList.add(new SelectItem(org.getGlobalid(), org.getOu()));
}
return selectItemsOrgList;
}
public List<SelectItem> returnAccessList() {
List<String> accessList = new ArrayList<String>();
List<SelectItem> selectItemsAccessList = new ArrayList<SelectItem>();
String userId = (String) getSessionMap().get(USER_ID_KEY);
accessList = getBusinessDelegate().getAccessList(userId, this.currentOrg);
if(accessList!=null){
for(String access : accessList){
selectItemsAccessList.add(new SelectItem(access, access));
}
}
return selectItemsAccessList;
}
public String goToOrderAccessPage(){
return "orderaccess.jsf";
}
}
Previously, i have orgList and accessList of String type, and validation error still exists.
Could someone help me? Thanks in advance!
UPDATE:
I change type of currentAccess to SelectItem and add attribute immediate="true" to command button but valueChangeListener method is not called.
Validation Error: Value is not valid
You will get this error when the submitted value does not match any of the available select items. In other words, the <f:selectItems> didn't return exactly the same items during the form submit as it did during the form display.
I change type of currentAccess to SelectItem
This is wrong. It should be the same type as the value property of SelectItem.
and add attribute immediate="true" to command button but valueChangeListener method is not called.
You don't need the valueChangeListener in this particular case. In the listener method you're just duplicating what JSF is already doing during update model values phase. Get rid of it. I have also the impression that you really don't need immediate="true" here. Remove it as well.

Resources