How to slide and refresh Primefaces charts - jsf

I'm really in trouble!
I need some brilliant idea to get a jsf page in which 7 charts slide one after another every 20 seconds and I need these charts are
refreshed every 30 seconds.
I tried some solutions with bad results:
1.Slideshow + Poll
<h:form>
<div align="center">
<p:panel id="chartcontainer" style="border: none;">
<p:imageSwitch style="width: 100%"
id="slider"
widgetVar="chartSlideShow"
effect="turnDown"
slideshowSpeed="5000">
<ui:include src="/charts/chart1.xhtml"/>
<ui:include src="/charts/chart2.xhtml"/>
<ui:include src="/charts/chart3.xhtml"/>
<ui:include src="/charts/chart4.xhtml"/>
<ui:include src="/charts/chart5.xhtml"/>
<ui:include src="/charts/chart6.xhtml"/>
<ui:include src="/charts/chart7.xhtml"/>
</p:imageSwitch>
</p:panel>
<p:poll widgetVar="pollWidget"
update="#form"
interval="30"
oncomplete="PF('btnPlayWidget').disable();"/>
</div>
</h:form>
This solution's problem is that the slideshow and poll are not synchronized so when I'm watching the chart3, for example, and poll is executed I don't expect the change and the slideshow restart from the first chart. This is really annoying!
2.Poll by itself
<h:form>
<div align='center'>
<p:panel id="chartcontainer" style="border: none;">
<ui:include src="#{slideView.slide}"/>
</p:panel>
<p:poll widgetVar="pollWidget"
update="#form"
interval="20"
listener="#{slideView.next()}"
oncomplete="PF('btnPlayWidget').disable();"/>
</div>
</h:form>
Here's my slideView's bean:
package com.tvop.beans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class SlideView implements Serializable {
private int index = 0;
String slide = "/charts/chart1.xhtml";
private final String[] slides = new String[] {
"/charts/chart1.xhtml",
"/charts/chart2.xhtml",
"/charts/chart3.xhtml",
"/charts/chart4.xhtml",
"/charts/chart5.xhtml",
"/charts/chart6.xhtml",
"/charts/chart7.xhtml"
};
public String getSlide() {
return slide;
}
public void setSlide(String slide) {
this.slide = slide;
}
public String next() {
index %= slides.length;
this.slide = slides[index];
index++;
return slide;
}
}
This solution runs more or less but the poll's interval is not exact, especially at the beginning, as soon as the page is loaded.
The first change between the first and the second chart happens after 30/35 seconds and not 20, as setted in the poll's interval.
I really need some good idea, I don't want to be fired.
Thank you all my friends!

Solved!
The solution is to use the poll component by its own; updating the poll every 20 seconds it emulates the imageSwitch behavior! It's important to modify the java bean too to make it work.
Following the solution:
xhtml poll:
<div align='center'>
<p:panel id="chartcontainer" style="border: none;">
<p:panel style="border: 0px">
<ui:include src="#{slideView.slide}" />
</p:panel>
</p:panel>
<p:poll widgetVar="pollWidget"
update="chartcontainer"
interval="20"
listener="#{slideView.next()}"
oncomplete="PF('btnPlayWidget').disable();"/>
</div>
slideview bean:
package com.tvop.beans;
import com.tvop.exceptions.DMLException;
import com.tvop.persistence.TkResourceJPA;
import com.tvop.persistence.dbentities.TkResource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
#ManagedBean
#ViewScoped
public class SlideView implements Serializable {
private SessionManager sessionManager = null;
private List<TkResource> resources;
private int index;
private String slide;
private final List<String> slides = new ArrayList<>();
public SlideView() {
// Ottengo i privilegi sui chart tramite il bean sessionManager
FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext extCtx = ctx.getExternalContext();
Map<String, Object> sessionMap = extCtx.getSessionMap();
sessionManager = (SessionManager) sessionMap.get("sessionManager");
try {
resources = TkResourceJPA.getCharts();
} catch (DMLException ex) {
ex.printStackTrace();
}
SessionPrivileges privileges = sessionManager.getSessionPrivileges();
for(TkResource resource : resources) {
// Se è definito un privilegio controllo che privilegio è
if (privileges.contains(resource.getResourceid())) {
boolean currentResRendered = privileges.getRendered(resource.getResourceid());
if(currentResRendered){
slides.add(resource.getUrl());
}
}
}
index = 0;
slide = slides.get(index);
}
public String getSlide() {
return slide;
}
public void setSlide(String slide) {
this.slide = slide;
}
public String next() {
index %= slides.size();
if (index == slides.size() - 1) {
index = -1;
}
index++;
this.slide = slides.get(index);
return slide;
}
public String previous() {
if (index == 0) {
index = slides.size();
}
--index;
this.slide = slides.get(index);
return slide;
}
}
Enjoy :)

Related

Primefaces Chart zoom and theme behaviour

I wanted to try out the primefaces library for jsf and see if it fits my needs in regards to dashboarding and chart creation. I tried setting up a dashboard with some fake data in a linechart to evaluate how it behaves:
<div style="height:500px">
<p:growl id="msgs" showDetail="true" />
<p:dashboard id="board" model="#{dashboardManagedBean.model}">
<p:ajax event="reorder" listener="#{dashboardManagedBean.handleReorder}" update="msgs" />
<p:panel width="100%" id="Finance" header="Finance" closable="true" toggleable="true">
<p:chart type="line" model="#{dashboardManagedBean.chartModel}" style="height:500px;"/>
</p:panel>
</p:dashboard>
</div>
This is the dashboard bean:
package com.journaldev.primefaces.beans;
import java.util.Date;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.primefaces.event.DashboardReorderEvent;
import org.primefaces.model.DashboardColumn;
import org.primefaces.model.DashboardModel;
import org.primefaces.model.DefaultDashboardColumn;
import org.primefaces.model.DefaultDashboardModel;
import org.primefaces.model.chart.*;
#ManagedBean
#SessionScoped
public class DashboardManagedBean {
private DashboardModel model;
private LineChartModel chartModel;
public DashboardManagedBean() {
// Initialize the dashboard model
this.model = new DefaultDashboardModel();
DashboardColumn column2 = new DefaultDashboardColumn();
column2.addWidget("Finance");
this.model.addColumn(column2);
chartModel = new LineChartModel();
chartModel.setTitle("Linear Chart");
chartModel.setLegendPosition("e");
chartModel.setZoom(true);
LineChartSeries series1 = new LineChartSeries();
series1.setLabel("Series 1");
chartModel.addSeries(series1);
Date date = new Date();
double y = 0;
for (int i=0;i<1000;i++){
series1.set(date.getTime() + 1000*i,y);
y+=Math.random();
}
DateAxis axis = new DateAxis("Dates");
axis.setTickAngle(-50);
axis.setTickFormat("%d.%m.%y %H:%#M:%S");
axis.setMin("09.09.18 17:38:00");
axis.setMax("09.09.18 18:00:00");
axis.setTickCount(12);
chartModel.getAxes().put(AxisType.X, axis);
}
public DashboardModel getModel() {
return model;
}
public LineChartModel getChartModel() {
return chartModel;
}
public void setModel(DashboardModel model) {
this.model = model;
}
}
And the result I got looks mostly good. The issues start coming in when I try zooming in the chart, then it gets really scuffed:
Zoomed Chart
So i have multiple concerns regarding primefaces charts:
Why is the theme I picked not applied? I installed the maven dependencies and added to the web.xml. For the rest of the dashboard it seems to work out.
Why does the zooming behave this weirdly?
Is there really no autoscaling on the linechart available for xmin and xmax?
Thanks for helping an absolute primefaces noob.

p:dashboard keep sort order after close

I want to use this primefaces dashboard
https://www.primefaces.org/showcase/ui/panel/dashboard.xhtml
dashboard.xhtml
<div style="height:500px">
<h:form>
<p:growl id="msgs" showDetail="true" />
<p:dashboard id="board" model="#{dashboardView.model}">
<p:ajax event="reorder" listener="#{dashboardView.handleReorder}" update="msgs" />
<p:panel id="sports" header="Sports">
<h:outputText value="Sports Content" />
</p:panel>
<p:panel id="finance" header="Finance">
<h:outputText value="Finance Content" />
</p:panel>
<p:panel id="lifestyle" header="Lifestyle">
<h:outputText value="Lifestyle Content" />
</p:panel>
<p:panel id="weather" header="Weather">
<h:outputText value="Weather Content" />
</p:panel>
<p:panel id="politics" header="Politics">
<h:outputText value="Politics Content" />
</p:panel>
</p:dashboard>
<div style="clear:both" />
</h:form>
</div>
DashBoardView.java
package org.primefaces.showcase.view.panel;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import org.primefaces.event.CloseEvent;
import org.primefaces.event.DashboardReorderEvent;
import org.primefaces.event.ToggleEvent;
import org.primefaces.model.DashboardColumn;
import org.primefaces.model.DashboardModel;
import org.primefaces.model.DefaultDashboardColumn;
import org.primefaces.model.DefaultDashboardModel;
#ManagedBean
#ViewScoped
public class DashboardView implements Serializable {
private DashboardModel model;
#PostConstruct
public void init() {
model = new DefaultDashboardModel();
DashboardColumn column1 = new DefaultDashboardColumn();
DashboardColumn column2 = new DefaultDashboardColumn();
DashboardColumn column3 = new DefaultDashboardColumn();
column1.addWidget("sports");
column1.addWidget("finance");
column2.addWidget("lifestyle");
column2.addWidget("weather");
column3.addWidget("politics");
model.addColumn(column1);
model.addColumn(column2);
model.addColumn(column3);
}
public void handleReorder(DashboardReorderEvent event) {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_INFO);
message.setSummary("Reordered: " + event.getWidgetId());
message.setDetail("Item index: " + event.getItemIndex() + ", Column index: " + event.getColumnIndex() + ", Sender index: " + event.getSenderColumnIndex());
addMessage(message);
}
public void handleClose(CloseEvent event) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Panel Closed", "Closed panel id:'" + event.getComponent().getId() + "'");
addMessage(message);
}
public void handleToggle(ToggleEvent event) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, event.getComponent().getId() + " toggled", "Status:" + event.getVisibility().name());
addMessage(message);
}
private void addMessage(FacesMessage message) {
FacesContext.getCurrentInstance().addMessage(null, message);
}
public DashboardModel getModel() {
return model;
}
}
It is very cool feature.
I make some drag&drop
and close tab of browser and open it again then all come to default.
I need somehow to keep this order.
Probably use cookies somehow or any other way. Is it possible and if yes how to do it?
Important is that the widget's order should be saved for every user. By this I mean one of two options:
every logged user can see this order in every devices
Without logging in browser but when open new browser the order should be by default. Or some other user open that order should be by default.
For sure not the best solution but a solution:
I guess I would save the events from handleReorder(DashboardReorderEvent event) in a database or in a file. And load the order in the postconstruct init. What do you think?
Edit like wrote in the comment it is not possible to serialize the event for me.
My second try is like this:
public void handleReorder(DashboardReorderEvent event) {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_INFO);
message.setSummary("Reordered: " + event.getWidgetId());
message.setDetail("Item index: " + event.getItemIndex() + ", Column index: " + event.getColumnIndex() + ", Sender index: " + event.getSenderColumnIndex());
addMessage(message);
serializeEvent(event);
}
The serializeEvent method does not serialize the event because this failed to me, but it serialize an Object with necessary informations.
private void serializeEvent(DashboardReorderEvent event) {
String userName = userBean.getUserName();
StackoverflowObject e = new StackoverflowObject(event);
try {
FileOutputStream fileOut =
new FileOutputStream("c:/tmp/events"+userName+".txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
//out.writeObject(event.getWidgetId()+";"+ event.getItemIndex()+";"+ event.getColumnIndex());
out.close();
fileOut.close();
} catch (Exception i) {
i.printStackTrace();
}
}
in the postconstruct init you read the serialized object and decide where to put the widget. This will show you the idea (it is nearly 1 a.m. so I show you just the beginning)
#PostConstruct
public void init() {
model = new DefaultDashboardModel();
DashboardColumn column1 = new DefaultDashboardColumn();
DashboardColumn column2 = new DefaultDashboardColumn();
DashboardColumn column3 = new DefaultDashboardColumn();
StackoverflowObject e = deserializeEvent("politics");
if (e != null &&"politics".equalsIgnoreCase(e.getWidgetId()) && e.getColumnId() == 0){
column1.addWidget("politics");
} else if (e != null &&"politics".equalsIgnoreCase(e.getWidgetId()) && e.getColumnId() == 1){
column2.addWidget("politics");
}
else{
column3.addWidget("politics");
}
.. do the same for all other widget
Now you have also the question to do it per user. The method deserializeEvent determinate the user and read the correct file for this user.
If you ask yourself how to get the user. In most cases like this
FacesContext.getCurrentInstance().getExternalContext().getRemoteUser()
If you have a loginbean like in my example you can get it from your userBean.
Edit the stackoverflowObject looks like this
public class StackoverflowObject implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4921468076398836905L;
private String widgetId;
private int columnId;
private int itenId;
public StackoverflowObject(DashboardReorderEvent event) {
this.setWidgetId(event.getWidgetId());
this.setColumnId(event.getColumnIndex());
this.setItenId(event.getItemIndex());
}
// +getter and setter

Primefaces: Form fields not synced with Managed Bean automatically

Have a nice day. I don't know if i'm wrong about this. I have a form in my xhtml like this:
<p:outputLabel value="Número de pasajeros" />:
<p:inputText value="#{vueloMB.instancia.numPasajeros}" maxlength="3" >
</p:inputText>
<br />
<p:outputLabel value="Hora de salida" />:
<p:calendar value="#{vueloMB.instancia.fechaHoraSalida}" navigator="true"
mode="popup" pattern="dd/MM/yyyy HH:mm" />
<br />
<p:outputLabel value="Avión" />:
<p:selectOneMenu value="#{vueloMB.instancia.avion}" >
<f:selectItems value="#{vueloMB.aviones}" var="avi"
itemLabel="#{avi.modelo}" itemValue="#{avi}" />
</p:selectOneMenu>
<br />
<p:outputLabel value="Pais de salida" />:
<p:selectOneMenu value="#{vueloMB.instancia.paisSalida}" converter="omnifaces.SelectItemsConverter" >
<f:selectItems value="#{vueloMB.paises}" var="pai"
itemLabel="#{pai.nombre}" itemValue="#{pai}" />
<f:param name="tipoPais" value="S"></f:param>
<p:ajax update="ciusal" listener="#{vueloMB.cargarListaCiudades}" process="#this" >
</p:ajax>
</p:selectOneMenu>
<br />
<p:outputLabel value="Ciudad de salida" />:
<p:selectOneMenu value="#{vueloMB.instancia.ciudadSalida}" converter="omnifaces.SelectItemsConverter"
id="ciusal" disabled="#{vueloMB.instancia.paisSalida==null}" >
<f:selectItems value="#{vueloMB.ciudadesSalida}" var="ciu"
itemLabel="#{ciu.nombre}" itemValue="#{ciu}" />
</p:selectOneMenu>
<br />
<p:commandButton value="Guardar" rendered="#{vueloMB.instancia.id == null}" action="#{vueloMB.guardar()}" process="#form" ajax="true" />
</h:form>
The dropdown labeled "Ciudad de salida" refreshes another dropdown after i choose a country here, updates the list that feeds the second dropdown and it works fine. The problem is when i press the "Guardar" button to save the entity (vueloMB.instancia is my entity) with JPA, because it doesn't do anything.
So, i added the attribute immediate="true" to the button, it calls the ManagedBean method, but when i see the entity, only the field vueloMB.instancia.paisSalida isn't null, even if i fill all the fields. Because of that, i assumed that, because the dropdown calls an MB method because it refresh the second dropdown, it's value is refreshed on the MB. Based on that, i modified the first field like this:
<p:inputText value="#{vueloMB.instancia.numPasajeros}" maxlength="3" >
<p:ajax />
</p:inputText>
I added the ajax tag to my inputText. After doing that, i press the "Guardar" button and the field that i've modified (Número de pasajeros) now it carries the value on vueloMB.instancia.numPasajeros.
So, if i add to all my fields, when i press the submit button it will work, it will save the entity without problems and all the fields will travel to the managed bean, but is necessary to do that with every field? There's no automatic way JSF does this? Or i have something wrong with my code?
EDIT: Here is the code of the managed bean. A CDI Managed Bean with #ConversationScoped:
package com.saplic.fut.beans;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import com.saplic.fut.daos.VueloDAO;
import com.saplic.fut.entity.Avion;
import com.saplic.fut.entity.Ciudad;
import com.saplic.fut.entity.Pais;
import com.saplic.fut.entity.Vuelo;
#Named("vueloMB")
#ConversationScoped
public class VueloManagedBean implements Serializable {
private static final long serialVersionUID = -203436251219946811L;
#Inject
private VueloDAO vueloDAO;
#Inject
private Conversation conversation;
#PostConstruct
public void iniciarConversacion() {
if(conversation.isTransient())
conversation.begin();
}
public void finalizarConversacion() {
if(!conversation.isTransient())
conversation.end();
}
private Vuelo instancia;
private List<Vuelo> vuelos;
private List<Avion> aviones = new ArrayList<Avion>();
private List<Pais> paises = new ArrayList<Pais>();
private List<Ciudad> ciudadesSalida = new ArrayList<Ciudad>();
private List<Ciudad> ciudadesAterrizaje = new ArrayList<Ciudad>();
private Integer idVuelo;
public String cargarLista() {
iniciarConversacion();
vuelos = vueloDAO.cargarVuelos();
return "/vuelos/lista";
}
public void cargarListaCiudades() {
String tipoLista = FacesContext.getCurrentInstance().
getExternalContext().getRequestParameterMap().get("tipoPais");
if(tipoLista.equalsIgnoreCase("S"))
setCiudadesSalida(vueloDAO.cargarCiudades(getInstancia().getPaisSalida()));
if(tipoLista.equalsIgnoreCase("A"))
setCiudadesAterrizaje(vueloDAO.cargarCiudades(getInstancia().getPaisAterrizaje()));
}
public String cargarDetalle() {
Vuelo fltVuelo = new Vuelo();
fltVuelo.setId(getIdVuelo());
instancia = vueloDAO.cargarDetalle(fltVuelo);
if(instancia == null)
setInstancia(new Vuelo());
//Cargamos lista de aviones para combo
setAviones(vueloDAO.cargarAviones());
setPaises(vueloDAO.cargarPaises());
return "/vuelos/detalle";
}
public String guardar() {
vueloDAO.guardar(instancia);
finalizarConversacion();
return cargarLista();
}
public String actualizar() {
vueloDAO.actualizar(instancia);
finalizarConversacion();
return cargarLista();
}
public String eliminar() {
vueloDAO.eliminar(instancia);
finalizarConversacion();
return cargarLista();
}
public Vuelo getInstancia() {
return instancia;
}
public void setInstancia(Vuelo instancia) {
this.instancia = instancia;
}
public List<Vuelo> getVuelos() {
return vuelos;
}
public void setVuelos(List<Vuelo> vuelos) {
this.vuelos = vuelos;
}
public Integer getIdVuelo() {
return idVuelo;
}
public void setIdVuelo(Integer idVuelo) {
this.idVuelo = idVuelo;
}
public List<Avion> getAviones() {
return aviones;
}
public void setAviones(List<Avion> aviones) {
this.aviones = aviones;
}
public List<Pais> getPaises() {
return paises;
}
public void setPaises(List<Pais> paises) {
this.paises = paises;
}
public List<Ciudad> getCiudadesSalida() {
return ciudadesSalida;
}
public void setCiudadesSalida(List<Ciudad> ciudadesSalida) {
this.ciudadesSalida = ciudadesSalida;
}
public List<Ciudad> getCiudadesAterrizaje() {
return ciudadesAterrizaje;
}
public void setCiudadesAterrizaje(List<Ciudad> ciudadesAterrizaje) {
this.ciudadesAterrizaje = ciudadesAterrizaje;
}
}
Regards.
Your entities must implements the method equals() hashCode() and toString as specified in the omnifaces showcase. I can't help you much more than that since I'm not familiar with omnifaces and the ConversationScope. I think it's because the two objects are not at the same place in memory so when you use equals the result is false. In the case of omnifaces I read it uses toString() to see if two objects are equal so if the method is not reimplemented you will have different results.
In other words you have null values because when the value as string comes back from the form it cannot be converted back to the original object. I'd appreciate if someone could attest this as I'm not 100% positive that's what is happening.

rich:progressBar currentValue does not working with For-Loop?

In RichFaces 4.1, rich:progressBar 'currentValue' from the ManagedBean does not updating with for-loop.
progressBar.xhtml
<h:form id="formProgress">
<h:commandLink action="#{progressBarBean.startProcess}" value="click here"/>
<rich:progressBar mode="ajax" value="#{progressBarBean.currentValue}" interval="1000" id="pb"
enabled="#{progressBarBean.enabled}" minValue="0" maxValue="100">
<h:outputText value="Retrieving #{progressBarBean.currentValue} of #{progressBarBean.totalRecords}" />
</rich:progressBar>
</h:form>
Bean
package ap;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class ProgressBarBean implements Serializable {
private static final long serialVersionUID = 8775622106408411357L;
private boolean enabled = false;
private Integer totalRecords;
private Integer currentValue;;
public String startProcess() {
setEnabled(true);
setTotalRecords(100);
return null;
}
public Integer getCurrentValue() {
if (isEnabled()) {
for(currentValue=0;currentValue < totalRecords;) {
currentValue++;
}
}
return currentValue;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Integer getTotalRecords() {
return totalRecords;
}
public void setTotalRecords(Integer totalRecords) {
this.totalRecords = totalRecords;
}
}
When i click the 'click here' link, the currentValue updates very fastly and reaches the totalRecords to 100 suddenly. It was not updating in the incremental way(present value in for-loop). The progress bar is not updated by the present value return by the method.
Any help please.
There are two problems: your Java code does not do what you want it to do and you're not telling the page to update (that won't happen automatically).
Take a look at the getCurrentValue() again: It increments currentValue from 0 to 100 and returns the result which is 100. #{progressBarBean.currentValue} does not care (or know) what happens with the variable, it only cares about the result of the getCurrentValue() method.
So in order for it all to work it will have to look like this:
Page
<a4j:commandLink action="#{progressBarBean.startProcess}" value="click here" render="pb" execute="#this"/>
<rich:progressBar mode="ajax" value="#{progressBarBean.currentValue}" interval="1000" id="pb"
enabled="#{progressBarBean.enabled}" minValue="0" maxValue="100">
<a4j:ajax event="begin" listener="#{progressBarBean.increment}" render="text"/>
<h:outputText value="Retrieving #{progressBarBean.currentValue} of #{progressBarBean.totalRecords}" id="text" />
</rich:progressBar>
The a4j:ajax is fired each second (i.e. each interval), it increments the currentValue and updates the text.
You also need a4j:commandLink (or a4j:ajax inside the h:commandLink) in order to rerender the progressbar - in your example you enable the progressbar in the bean but the value on the page does not change.
Bean
public Integer getCurrentValue() {
return currentValue;
}
public void increment() {
if (isEnabled() && currentValue < totalRecords) {
currentValue++;
}
}
Ask if anything isn't clear.

Magic ui:repeat var

I have stumbled upon an, at least for me, unexpected behaviour. When using an ui:repeat, it seems I can access the var from outside.
Code - Page:
<f:metadata>
<f:event type="preRenderView" listener="#{xTest.init()}" />
</f:metadata>
<h:form id="xTestForm">
<h:panelGroup layout="block">
Track: #{trk.name}
</h:panelGroup>
<table>
<ui:repeat
value="#{xTest.trackList}"
var="trk">
<tr>
<td>#{trk.name}</td>
<td>
<p:commandLink
actionListener="#{xTest.setTrack(track)}"
value="test"
update=":xTestForm" />
</td>
</tr>
</ui:repeat>
</table>
</h:form>
Code - Bean
package beans;
import dao.DAOFactory;
import dao.track.TrackDAO;
import dto.Track;
import exceptions.DAOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import util.MessageUtil;
#ManagedBean
#ViewScoped
public class xTest implements Serializable {
private DAOFactory daoFactory = Config.getInstance().getDAOFactory();
private TrackDAO trackDAO;
private Track track = new Track();
private MessageUtil msg = new MessageUtil();
private List<Track> trackList = new ArrayList();
public xTest() {
trackDAO = daoFactory.getTrackDAO(true);
}
public void init() {
if (!FacesContext.getCurrentInstance().isPostback()) {
try {
trackList = trackDAO.listByAlbumid(241);
} catch (SQLException | DAOException ex) {
msg.setErrorMessage(ex);
}
}
}
public List<Track> getTrackList() {
return trackList;
}
public void setTrack(Track track) {
this.track = track;
}
}
If I click a link in the list of tracks, the track name will be displayed in the panelGroup. How is this possible?
This is a bug in Mojarra. Its UIRepeat component forgets to remove the iteration variable from the request scope by end of iteration during restore view phase. It doesn't work that way in for example MyFaces.
You shouldn't rely your business code on it. Note that <h:dataTable> doesn't have this problem, it properly removes the iteration variable from the request scope by end of iteration by ((UIData) component).setRowIndex(-1) in encodeEnd() method.
8 years later someone reported this to PrimeFaces so I opened a Mojarra issue and a PR to fix the issue.
Mojarra Issue: https://github.com/eclipse-ee4j/mojarra/issues/4830
Mojarra PR: https://github.com/eclipse-ee4j/mojarra/pull/4831

Resources