jsf search and result pages - jsf

I have two pages - search and result and one bean. If I use ViewScoped, my results do not show. If I use RequestScoped, my page links do not work. How can I fix it? If I place the submit into init with Viewscoped, everything is working fine, but if I do that, how should I get the variables from the form?
My bean:
#Named
#ViewScoped
public class Result implements Serializable {
private static final long serialVersionUID = 1L;
private DAOFactory javabase = DAOFactory.getInstance("javabase.jdbc");
private RecipeDAO recipeDAO = javabase.getRecipeDAO();
private ResourceBundle messages;
#Inject
LocaleBean locale;
private List<Recipe> recipes;
private List<Recipe> recipesView;
private String language;
private List<Page> pagesArray;
private Integer currentPage;
public void init() {
System.out.println("Language is: " + language);
String language1 = "en";
recipes = new ArrayList<>();
recipes = recipeDAO.searchRecipe(language1);
int showValue = 5; //split value
int pages = recipes.size() / showValue; //pages value
if (recipes.size() % showValue != 0) {
pages = pages + 1;
}
for (int i = 0; i < recipes.size(); i++) {
int a = i + 1;
//System.out.println("i is: " + i + " recipe number is: " + a);
}
//System.out.println("pages is: " + pages + " size is: " + recipes.size());
pagesArray = new ArrayList<>();
Page page;
for (int i = 0; i < recipes.size(); i = i + showValue) {
page = new Page();
page.setPageDisabled(false);
page.setFirstItem(i);
page.setLastItem(i + showValue - 1);
pagesArray.add(page);
}
for (int i = 0; i < pagesArray.size(); i++) {
pagesArray.get(i).setPageNumber(i + 1);
}
pagesArray.get(pagesArray.size() - 1).setLastItem(recipes.size() - 1);
/* for (int i = 0; i < pagesArray.size(); i++) {
System.out.println(pagesArray.get(i).getPageNumber() + " " + pagesArray.get(i).getFirstItem() + " " + pagesArray.get(i).getLastItem() + " " + pagesArray.get(i).isPageDisabled());
}*/
recipesView = new ArrayList<>();
Recipe recipe;
for (int i = pagesArray.get(0).getFirstItem(); i <= pagesArray.get(0).getLastItem(); i++) {
recipe = new Recipe();
recipe.setAuthor(recipes.get(i).getAuthor());
recipe.setId(recipes.get(i).getId());
recipe.setCreateDate(recipes.get(i).getCreateDate());
recipe.setTitle(recipes.get(i).getTitle());
recipesView.add(recipe);
}
pagesArray.get(0).setPageDisabled(true);
}
public void doPages() {
FacesContext fc = FacesContext.getCurrentInstance();
this.currentPage = Integer.parseInt(getCountryParam(fc));
System.out.println(currentPage);
recipesView = new ArrayList<>();
Recipe recipe;
for (int i = pagesArray.get(currentPage - 1).getFirstItem(); i <= pagesArray.get(currentPage - 1).getLastItem(); i++) {
System.out.println(i);
recipe = new Recipe();
recipe.setAuthor(recipes.get(i).getAuthor());
recipe.setId(recipes.get(i).getId());
recipe.setCreateDate(recipes.get(i).getCreateDate());
recipe.setTitle(recipes.get(i).getTitle());
recipesView.add(recipe);
}
for (int i = 0; i < pagesArray.size(); i++) {
pagesArray.get(i).setPageDisabled(false);
}
pagesArray.get(currentPage - 1).setPageDisabled(true);
}
public String getCountryParam(FacesContext fc) {
Map<String, String> params = fc.getExternalContext().getRequestParameterMap();
return params.get("currentPage");
}
//setters&getters
}
My search view:
<h:form>
<h:selectOneMenu value="#{search.language}">
<f:selectItem itemLabel="English" itemValue="en"/>
<f:selectItem itemLabel="Select" itemValue=""/>
<f:selectItem itemLabel="Bulgarian" itemValue="bg"/>
</h:selectOneMenu>
<h:commandButton value="Submit" type="submit" action="#{search.submit()}">
<f:param name="lang" value ="#{search.language}"/>
</h:commandButton>
</h:form>
My result view:
<f:metadata>
<f:viewParam name="lang" value="#{result.language}" />
<f:viewAction action="#{result.init()}" />
</f:metadata>
<h:form>
<ui:repeat value="#{result.recipesView}" var="rec">
<h:link value="#{rec.title}" outcome="recipeshow">
<f:param name="id" value="#{rec.id}" />
</h:link>
<br/>
<h:outputText value="#{rec.id}"/><br/>
<h:outputText value="#{rec.author}"/><br/>
<h:outputText value="#{rec.createDate}"/><br/>
<br/>
</ui:repeat>
<br/>
<ui:repeat value="#{result.pagesArray}" var="page">
<h:commandLink value="#{page.pageNumber}" disabled="#{page.pageDisabled}">
<f:ajax listener="#{result.doPages()}" render="#form"/>
<f:param name="currentPage" value="#{page.pageNumber}"/>
</h:commandLink>
</ui:repeat>
</h:form>
My page.java
public class Page {
private int pageNumber;
private boolean pageDisabled;
private int firstItem;
private int lastItem;
public int getPageNumber() {
return pageNumber;
}
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
public boolean isPageDisabled() {
return pageDisabled;
}
public void setPageDisabled(boolean pageDisabled) {
this.pageDisabled = pageDisabled;
}
public int getFirstItem() {
return firstItem;
}
public void setFirstItem(int firstItem) {
this.firstItem = firstItem;
}
public int getLastItem() {
return lastItem;
}
public void setLastItem(int lastItem) {
this.lastItem = lastItem;
}
}

You returned a navigation case outcome from an action method, so your view scoped bean will be recreated, that's why you don't see your results. On the other hand, as you seem to be doing a pagination basing on the information held in the view scope, thus your request scoped beans do not allow for proper pagination.
As to the solution, you should either be doing a postback from your action method, thus returning null or void, or pass the necessary information to the result view using get parameters.
It is also worth noting that you're preloading too much information in recipes = recipeDAO.searchRecipe(language);: you should be loading as much information as is shown in your view, like in: recipes = recipeDAO.searchRecipe(language, min, max);.

Related

jsf static list won't show up in datatable

I'm trying to get a list to show in datatable from managed bean to JSF page but it doesn't work.
it's telling me " not records found " .
JSF managed bean :
#ManagedBean
#RequestScoped
public class TestController {
private List<Rhnom> list = new ArrayList<Rhnom>();
#SuppressWarnings("serial")
private List<String> list2 = new ArrayList<String>() {{
add("s1");
add("s2");
add("s3");
}};
//getters and setters
JSF page :
<p:dataTable value="#{tesController.list2}" var="type">
<p:column headerText="Lib">
<h:outputText value="#{type}">
</h:outputText>
</p:column>
</p:dataTable>
I consider that you have problems with the implementation
Link
https://www.primefaces.org/showcase/ui/data/datatable/basic.xhtml
Example
<p:dataTable var="car" value="#{dtBasicView.cars}">
<p:column headerText="Id">
<h:outputText value="#{car.id}" />
</p:column>
<p:column headerText="Year">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Brand">
<h:outputText value="#{car.brand}" />
</p:column>
<p:column headerText="Color">
<h:outputText value="#{car.color}" />
</p:column>
</p:dataTable>
Managebean
#Named("dtBasicView")
#ViewScoped
public class BasicView implements Serializable {
private List<Car> cars;
#Inject
private CarService service;
#PostConstruct
public void init() {
cars = service.createCars(10);
}
public List<Car> getCars() {
return cars;
}
public void setService(CarService service) {
this.service = service;
}
}
Java Class
#Named
#ApplicationScoped
public class CarService {
private final static String[] colors;
private final static String[] brands;
static {
colors = new String[10];
colors[0] = "Black";
colors[1] = "White";
colors[2] = "Green";
colors[3] = "Red";
colors[4] = "Blue";
colors[5] = "Orange";
colors[6] = "Silver";
colors[7] = "Yellow";
colors[8] = "Brown";
colors[9] = "Maroon";
brands = new String[10];
brands[0] = "BMW";
brands[1] = "Mercedes";
brands[2] = "Volvo";
brands[3] = "Audi";
brands[4] = "Renault";
brands[5] = "Fiat";
brands[6] = "Volkswagen";
brands[7] = "Honda";
brands[8] = "Jaguar";
brands[9] = "Ford";
}
public List<Car> createCars(int size) {
List<Car> list = new ArrayList<Car>();
for(int i = 0 ; i < size ; i++) {
list.add(new Car(getRandomId(), getRandomBrand(), getRandomYear(), getRandomColor(), getRandomPrice(), getRandomSoldState()));
}
return list;
}
private String getRandomId() {
return UUID.randomUUID().toString().substring(0, 8);
}
private int getRandomYear() {
return (int) (Math.random() * 50 + 1960);
}
private String getRandomColor() {
return colors[(int) (Math.random() * 10)];
}
private String getRandomBrand() {
return brands[(int) (Math.random() * 10)];
}
private int getRandomPrice() {
return (int) (Math.random() * 100000);
}
private boolean getRandomSoldState() {
return (Math.random() > 0.5) ? true: false;
}
public List<String> getColors() {
return Arrays.asList(colors);
}
public List<String> getBrands() {
return Arrays.asList(brands);
}
}

Bind list of list in JSF

This is my class as model which have 2 lists as key value pairs. One sample consists of many key value pairs. And I want to iterate this sample's list on view of the same bean class.
public class Sample {
List<String> sampleKey;
List<String> sampleValue;
boolean editable;
public Sample(List<String> sampleKey, List<String> sampleValue) {
this.sampleKey = sampleKey;
this.sampleValue = sampleValue;
}
public boolean isEditable() {
return editable;
}
public void setEditable(boolean editable) {
this.editable = editable;
}
public List<String> getsampleKey() {
return sampleKey;
}
public void setsampleKey(List<String> sampleKey) {
this.sampleKey = sampleKey;
}
public List<String> getsampleValue() {
return sampleValue;
}
public void setsampleValuee(List<String> sampleValue) {
this.sampleValue = sampleValue;
}
}
public ArrayList<Sample> sampleList;
Sample sam = null;
sampleList = new ArrayList<Sample>();
List<Map.Entry<String, List<String>>> entryList = new ArrayList<>(records.entrySet());
for (int j = 0; j < maxSamples; j++) {
ArrayList<String> sampleKey = new ArrayList<>();
ArrayList<String> sampleValue = new ArrayList<>();
for (int i = 7; i < records.size(); i++) {
List<String> sample = entryList.get(i).getValue();
if (!sample.isEmpty()) {
sampleKey.add(keyList.get(i));
if (!sample.get(j).isEmpty()) {
sampleValue.add(sample.get(j));
}
}
}
sam = new Sample(sampleKey, sampleValue);
sampleList.add(sam);
}
Now here is my view of same bean class:
<ui:repeat value="#{dataEntryFormController.sampleList}"
var="key" varStatus="recordMetadata">
<h:dataTable
value="#{dataEntryFormController.sampleList[recordMetadata.index]}"
var="o" binding="#{table}">
<h:column>
<h:inputText value="#{o.sampleKey[table.rowIndex]}" size="10" rendered="#{o.editable}" />
<h:outputText value="#{o.sampleKey[table.rowIndex]}" rendered="#{not o.editable}" />
</h:column>
<h:column>
<h:inputText value="#{o.sampleValue[table.rowIndex]}" size="20"rendered="#{o.editable}" />
<h:outputText value="#{o.sampleValue[table.rowIndex]}" rendered="#{not o.editable}" />
</h:column>
</h:dataTable>
</ui:repeat>
In my JSF page, I want to bind that list of list to view for iterating over a number of samples and each sample may have many key value pairs. With the above code, I can only print 1 key value pair at a time.
I am having issue in binding.

Using P:CommandButton in PrimeFaces

Originally I have this form for user input and do a search.
<h:form id="wordForm">
<h:panelGrid columns="4">
<h:inputText id="word" "
value="#{wordController.word}" />
<h:message for="word" />
<h:commandButton id="search" value="search"
action="#{wordController.search}" />
</h:panelGrid>
</h:form>
Now I want to use PrimeFaces for autocomplete feature, and this is my new form with Autocomplete. How can I replace the new form with the above form?
<h:form>
<p:growl id="msgs" showDetail="true" />
<h:panelGrid columns="2" cellpadding="5">
<p:autoComplete id="wordForm" value="#{autoCompleteView.query}"
completeMethod="#{autoCompleteView.completeQuery}" var="query"
itemLabel="#{query.displayName}" itemValue="#{query}"
converter="queryConverter" forceSelection="true" />
<p:commandButton value="search" oncomplete="PF('dlg').show()" **action="#{wordController.search}"** />
</h:panelGrid>
</h:form>
More specifically, I think I still need to somehow use "action="#{wordController.search}" in P:CommandAction button so that I don't need to change anything else in backend. But How do I pass the query parameter to the "wordController.word" variable? Because now "action="#autoCompleteView.query" takes the user input.
How can I modify this without significant change to current bean code? Do I have to unify the original search bean WordController with the new AutocompleteView bean? because now the user input is accepted into AutoCompleteView bean.
AutoCompleteView.java
#ManagedBean
public class AutoCompleteView {
private Query query;
#ManagedProperty("#{queryService}")
private QueryService service;
private List<Query> selectedQueries;
public List<Query> completeQuery(String query) {
System.out.println(query);
List<Query> allQueries = service.getQueries();
List<Query> filteredQueries = new ArrayList<Query>();
for (int i = 0; i < allQueries.size(); i++) {
Query skin = allQueries.get(i);
if(skin.getName().toLowerCase().contains(query)) {
filteredQueries.add(skin);
}
}
return filteredQueries;
}
public void onItemSelect(SelectEvent event) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Item Selected", event.getObject().toString()));
}
public Query getQuery() {
return query;
}
public void setQuery(Query query) {
this.query = query;
}
public void setService(QueryService service) {
this.service = service;
}
public List<Query> getSelectedQueries() {
return selectedQueries;
}
public void setSelectedQueries(List<Query> selectedQueries) {
this.selectedQueries = selectedQueries;
}
}
Edited per suggestion:
#Named
#RequestScoped
public class WordController {
private String word;
// For AutoComplete suggestions
private Query selectedQuery;
#Inject
private QueryService service;
#Inject
private Word wordObject;
public void search() {
if (word != null && !word.isEmpty()) {
wordObject.searchWord(word);;
...
}else {
System.out.println("Query can't be null!");
}
}
public List<Query> completeQuery(String query) {
List<Query> allQueries = service.getQueries();
List<Query> filteredQueries = new ArrayList<Query>();
for (int i = 0; i < allQueries.size(); i++) {
Query skin = allQueries.get(i);
if(skin.getName().toLowerCase().contains(query)) {
filteredQueries.add(skin);
}
}
return filteredQueries;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public Query getSelectedQuery() {
return selectedQuery;
}
public void setSelectedQuery(Query selectedQuery) {
this.selectedQuery = selectedQuery;
}
}
Question: Originally, my 'word' is filled through an "h:inputText" in JSF view and search() is called in JSF:
<h:commandButton id="search" value="Search!" action="#{wordController.search}" />
Now, how do I get "selectedQuery" from completeQuery() method, and then use it to fill "word" and then call search() method?

How to do pagination in JSF 2

I am very new to JSF and was trying to implement a pagination using <ui:repeat>. I am using the #ViewScoped but currently my state is not saved. Every time the backing bean resets the page information and the next page is not displayed. Attaching the source code for reference.
WorkItemList.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
template="/WEB-INF/template/default.xhtml">
<ui:define name="content">
<h:form id="form">
<ui:repeat value="#{repeatPaginator.model}" var="listItem">
<div>
<h:outputText value="#{listItem}"/>
</div>
</ui:repeat>
<h:commandButton value="< prev" action="#{repeatPaginator.prev}"/>
<h:outputText value="#{repeatPaginator.pageIndex} / #{repeatPaginator.pages}"/>
<h:commandButton value="next >" action="#{repeatPaginator.next}"/>
<h:inputHidden value="#{repeatPaginator.pageIndex}"/>
</h:form>
</ui:define>
</ui:composition>
Backing Bean - RepeatPaginator.java
package test;
#ManagedBean
#ViewScoped
public class RepeatPaginator implements Serializable{
private static final long serialVersionUID = 1L;
private static final int DEFAULT_RECORDS_NUMBER = 2;
private static final int DEFAULT_PAGE_INDEX = 1;
private TestDelegate delegate;
private int records;
private int recordsTotal;
private int pageIndex;
private int pages;
private List<String> model;
public RepeatPaginator() {
delegate = new TestDelegate();
this.records = DEFAULT_RECORDS_NUMBER;
this.pageIndex = DEFAULT_PAGE_INDEX;
// Get Model
this.model = delegate.fetchCurrentList(getFirst(), getFirst()+records);
this.recordsTotal = delegate.getListSize();
if (records > 0) {
pages = records <= 0 ? 1 : recordsTotal / records;
if (recordsTotal % records > 0) {
pages++;
}
if (pages == 0) {
pages = 1;
}
} else {
records = 1;
pages = 1;
}
updateModel();
}
public void updateModel() {
int fromIndex = getFirst();
int toIndex = getFirst() + records;
if(toIndex > this.recordsTotal) {
toIndex = this.recordsTotal;
}
setModel(delegate.fetchCurrentList(fromIndex, toIndex));
}
public void next() {
if(this.pageIndex < pages) {
this.pageIndex++;
}
updateModel();
}
public void prev() {
if(this.pageIndex > 1) {
this.pageIndex--;
}
updateModel();
}
public int getRecords() {
return records;
}
public int getRecordsTotal() {
return recordsTotal;
}
public int getPageIndex() {
return pageIndex;
}
public int getPages() {
return pages;
}
public int getFirst() {
return (pageIndex * records) - records;
}
public List<String> getModel() {
if(model==null)
updateModel();
return model;
}
public void setModel(List<String> model) {
this.model = model;
}
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
}
}
Delegate - TestDelegate.java
#ViewScoped
public class TestDelegate {
private List<String> list = new ArrayList<String>();
public TestDelegate()
{
this.list.add("Item 1");
this.list.add("Item 2");
this.list.add("Item 3");
this.list.add("Item 4");
this.list.add("Item 5");
this.list.add("Item 6");
this.list.add("Item 7");
this.list.add("Item 8");
this.list.add("Item 9");
this.list.add("Item 10");
this.list.add("Item 11");
}
public List<String> fetchCurrentList(int from, int to)
{
return list.subList(from, to);
}
public int getListSize()
{
return this.list.size();
}
}
The #ViewScoped bean is not "magically present all the time". At the end of the request, it's values will be serialized and the bean is destructed.
This causes a Re-Construct of the bean at the beginning of the next request (click on next). Your Container will take care to deserialize the stored values again, in order to return the actual State of the bean. BUT: This happens after Bean-Construction, meaning when you try to use the values within the Constructor of the bean, nothing is restored.
Move your logic into a method that you annotate with #PostConstruct - then all values will be loaded and you can fetch the correct result. The container will call the method annotated with #PostConstruct once it restored the prior state of the bean.
This becomes important when you start to use ManagedProperties or CDI-Injections.
public RepeatPaginator() {
//no serialized data available here, Good location to initialize some stuff
//that is independent.
delegate = new TestDelegate();
this.records = DEFAULT_RECORDS_NUMBER;
this.pageIndex = DEFAULT_PAGE_INDEX;
}
#PostConstruct
public void init() {
//Here the ViewScoped values are restored. We can start to use them.
// Get Model
this.model = delegate.fetchCurrentList(getFirst(), getFirst()+records);
this.recordsTotal = delegate.getListSize();
if (records > 0) {
pages = records <= 0 ? 1 : recordsTotal / records;
if (recordsTotal % records > 0) {
pages++;
}
if (pages == 0) {
pages = 1;
}
} else {
records = 1;
pages = 1;
}
updateModel();
}

primefaces reload galleria

reference: http://www.primefaces.org/showcase/ui/galleria.jsf
my page:
<p:galleria id="merchant-gallery" value="#{testController.imageIds}" var="item" autoPlay="false" >
<p:graphicImage width="300" value="#{imageStreamer.image}" >
<f:param name="id" value="#{item}" />
</p:graphicImage>
</p:galleria>
i tried enclosing <p:galleria> in a form and added a <p:remoteCommand name="updateme" update="#form"/> but after calling updateme it simply just make the galleria blank.
*Update
testController bean:
public List<Integer> getImageIds() {
int aId = (Integer) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("user_id");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("TEST2PU");
EntityManager em = emf.createEntityManager();
TypedQuery<Merchant> tp = em.createQuery("SELECT a FROM Account a WHERE a.id = :id", Account.class);
tp.setParameter("id", aId);
current = tp.getSingleResult();
Collection rawPhotoCollection = current.getPhotoCollection();
imageIds = new ArrayList<Integer>(rawPhotoCollection);
List<Photo> photoList = new ArrayList<Photo>(rawPhotoCollection);
for (int i = 0; i < photoList.size(); i++) {
int imageId = photoList.get(i).getId();
imageIds.set(i, imageId);
}
return imageIds;
}
imageStreamer bean:
#EJB
private test.controller.photo.PhotoFacade ejbFacade;
public StreamedContent getImage() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
Map<String, String> param = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String id = param.get("id");
Photo image = ejbFacade.find(Integer.valueOf(id));
return new DefaultStreamedContent(new ByteArrayInputStream(image.getImage()));
}
}
I reworked your example and have the same issue. It is not related to your upload or remotecommand. I think it is a bug in primefaces. See http://code.google.com/p/primefaces/issues/detail?id=4840 for similar issue.
When I do the command
PrimeFaces.cw('Galleria','widget_companydetail_merchant-gallery',{id:'companydetail:merchant-gallery',transitionInterval:0,panelWidth:640,panelHeight:480,custom:false},'galleria');
in firebug console, the galleria reappears.
So when changing the remotecommand and adding the javascript to oncomplete it works.
<p:remoteCommand name="updateme" update="#form" oncomplete="PrimeFaces.cw('Galleria','widget_companydetail_merchant-gallery',{id:'companydetail:merchant-gallery',transitionInterval:0,panelWidth:640,panelHeight:480,custom:false},'galleria');"/>

Resources