Language switcher implementation in JSF - jsf

I have a complex jsf page with some widgets developed in PrimeFaces. Up to now, the application is completely ajaxified, meaning that there aren't submits, but all the events and updates are handled through Ajax behavior (this is not a must, but a nice-to-have feature). I have also done a SelectOneMenu for switching the language:
<h:form>
<p:panelGrid columns="2" >
<h:outputText value="#{msgs.SelectLanguage}" />
<p:selectOneMenu value="#{languageSwitcher.selectedLanguage}" >
<f:selectItems value="#{languageSwitcher.languages}" ></f:selectItems>
</p:selectOneMenu>
</p:panelGrid>
</h:form>
The switcher works well.
My problem is how to reload the translated messages when a language is selected.
I have tried these options:
Option 1
With an ajax update inside the selectOneMenu:
<p:ajax update="myFormsTobeUpdated" ></p:ajax>
This works great, and is the preferred solution because it's Ajax, but
EDITED
this solution doesn't ajax-update the Tab titles in the PrimeFaces TabView, and this is problem is blocking because the Tab titles need to be translated.
Option 2
With a complete reload of the page in Javascript. I have tried this but doesn't work (can't tell why):
<p:selectOneMenu value="#{languageSwitcher.selectedLanguage}" onchange="window.location.reload()" >
Option 3
With a complete reload of the page in Java like explained here: https://stackoverflow.com/a/1821708/870122 (to be honest I haven't tried it yet, but will do soon!)
Any suggestions are welcome.

If you're using at least PrimeFaces 3.2, then you can use
<p:ajax update="#all" />
to update the entire view. Before this version, the #all wasn't supported.

In your Form:
<h:selectOneRadio value="#{localeBean.language}"
onchange="submit()">
<f:selectItems value="#{collection.listLangs()}" var="s"
itemLabel="${s.description}" itemValue="${s.code}" />
</h:selectOneRadio>
but your not have a collection (REMEMBER, IN YOUR FORM):
<h:selectOneMenu value="#{localeBean.language}"
onchange="submit()">
<f:selectItem itemValue="en" itemLabel="English" />
<f:selectItem itemValue="es" itemLabel="Español" />
</h:selectOneMenu>
IN Primefaces, use this: p:selectOneMenu
In your Bean:
import java.lang.invoke.MethodHandles;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#ManagedBean
#SessionScoped
public class LocaleBean {
private static final Logger LOG = LogManager.getLogger(MethodHandles.lookup().lookupClass());
private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
public Locale getLocale() {
return locale;
}
public String getLanguage() {
return locale.getLanguage();
}
public void setLanguage(String language) {
LOG.info("Vamos a Cambiar a: " + language);
locale = new Locale(language);
LOG.info("Vamos a Cambiar a: " + locale.getDisplayName() + FacesContext.getCurrentInstance().getViewRoot());
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
}

Since with Option 1 it's not possible to ajax-update the Tab titles in the PrimeFaces TabView, I have switched to Option 2, a complete reload of the page using JavaScript.
The code that makes it work is:
<h:form id="selectLanguage">
<p:panelGrid columns="2">
<h:outputText value="#{msgs.SelectLanguage}" />
<p:selectOneMenu value="#{languageSwitcher.selectedLanguage}" onchange="document.getElementById('selectLanguage').submit();" >
<f:selectItems value="#{languageSwitcher.languages}" ></f:selectItems>
</p:selectOneMenu>
</p:panelGrid>
</h:form>

Related

p:selectOneMenu in p:panel no load correct after save

I'm using STS (Spring tool suite) with spring boot, primefaces and hibernate.
I have an page with a p:datatable. In the last column, have a p:commandbutton for edit data of the table (p:dialog).
When I open the dialog, all data load correct. If I close de dialog without save and open other line of the table data load correct again, but, if I save the data and open a new dialog of other line of the table, the field p:selectOneMenu is loaded with wrong data. Your value is the same value of the last dialog saved. All dialog data has correct, less the combobox (p:selectOneMenu). In debug, the value returned in backing bean is correct.
Some things I've tried:
Changed p:commandbutton to p:commandlink;
In button "save" of dialog, "update" field with the p:panel of table, the h:form, h:datable;
Change onComplete to onClick;
Use h:selectOneMenu instead of p:selectOneMenu;
Downgrade primefaces (currently 6.1) and myfaces (currently 2.2.12).
All no sucess.
ps: Datatable is filtered and paginated.
xhtml:
<p:panel id="pnlData" header="My Table">
<h:form id="frmTable">
<p:dataTable var="item" value="#{RSDMBean.myData}"
id="tblTicketsID" widgetVar="tabelaTickets" some things of pagination and filters here...>
<p:column />
<p:column /> ...
<p:column headerText="Edit">
<p:commandButton value="Edit"
actionListener="#{RSDMBean.editTicketLoad(item.idTicket)}"
update=":formPnl:pnlTkct" oncomplete="PF('dlgtkt').show();">
</p:commandButton>
</p:column>
</p:datatable>
</h:form
</p:panel>
<p:dialog id="dlgtktID" header="Edit ticket" widgetVar="dlgtkt"
modal="true">
<h:form id="formPnl">
<h:panelGrid id="pnlTkct" columns="2" cellpadding="10"
cellspacing="1" style="absolute">
<h:outputText style="font-weight:bold" value="Id Ticket: " />
<h:outputText value="#{RSDMBean.ticketEdited.id}" />
Others fields here...
<h:outputText style="font-weight:bold" value="County: " />
<p:selectOneMenu style="min-width: 162px;" required="true">
<f:selectItem itemLabel="#{RSDMBean.ticketEdited.county.name}"
itemValue="#{RSDMBean.ticketEdited.county.id}" />
<f:selectItems
value="#{RSDMBean.countyItensedit.entrySet()}" var="entry"
itemValue="#{entry.key}" itemLabel="#{entry.value}" />
</p:selectOneMenu>
<p:commandButton value="Save" action="#{RSDMBean.saveEdit}"
update=":frmTable:tblTicketsID" oncomplete="PF('dlgtkt').hide();" />
end tags here...
Bean:
import javax.annotation.PostConstruct;
import javax.faces.bean.RequestScoped;
import org.springframework.beans.factory.annotation.Autowired;
.
.
.
#Controller("RSDMBean")
#RequestScoped
public class MyMBean implements Serializable {
#Autowired
private ResiduoService residuoService;
#Autowired
private ResiduoRepository residuoRepository;
#Autowired
private CountyRepository countyRepository;
private Residuo ticketEdited;
private List<County> county;
private Map<Long, String> countyItensEdit = new HashMap<Long, String>();
public void editTicketLoad(String param) {
long idTicket = Long.parseLong(param);
ticketEdited = residuoRepository.findOne(idTicket);
county = countyRepository.findAll();
}
#PostConstruct
public void construct() {
//some loads database here...
county = countyRepository.findAll();
if (countyItensEdit.isEmpty()) {
for (Municipio c : countyItensEdit) {
countyItensEdit.put(c.getId(), c.getNome());
}
}
}
In p:selectOneMenu was missing value tag:
<p:selectOneMenu style="min-width: 162px;" required="true"
value="#{RSDMBean.ticketEdited.county.id}">

FacesComponent works in one page but doesn't in others (retrieves null from ajax event)

I don't know if there's a solved question for that. If so, I wasn't able to find it.
I'm creating a composite component with two SelectOneMenu that fires an event.
The thing is that this component works in one jsf but doesn't in others.
The component is inside three different xhtml. In all of them the event is fired when I change the value of the first SelectOneMenu, but only in one of the xhtml the value of the SelectItem is not null. In the rest of them, the retrieved value is "null"
//In p001DatosNotificacion.xhtml, it retrieves the selected value of the selectonemenu (b, for example)
//In the others it retrieves null
UISelectOne oneVoewl = (UISelectOne)event.getSource();
System.out.println("One Voewl > " + oneVoewl.getValue());
Can anyone help me and tell me where I'm making the mistake(s)?
Thanks in advance!
The code
Component backing bean
#FacesComponent(value="letterExample")
public class LetterExample extends UINamingContainer{
public void voewlAjaxListener(AjaxBehaviorEvent event){
UISelectOne oneVoewl = (UISelectOne)event.getSource();
System.out.println("One Voewl > " + oneVoewl.getValue());
}
Composite component (Note: I'm using an existing bean for testing)
<cc:interface componentType="letterExample" >
<cc:attribute name="bean" type="es.ccasa.sgnx.business.bean.Direccion" />
</cc:interface>
<cc:implementation>
<p:selectOneMenu id="oneMenuVoewl" value="#{cc.attrs.bean.codigoPais}"
binding="#{cc.uiSelectOneVoewl}" >
<f:selectItem itemLabel="Aaaa" itemValue="a" />
<f:selectItem itemLabel="Eeee" itemValue="e" />
<f:selectItem itemLabel="Iiii" itemValue="i" />
<f:selectItem itemLabel="Oooo" itemValue="o" />
<f:selectItem itemLabel="Uuuu" itemValue="u" />
<p:ajax event="change" listener="#{cc.voewlAjaxListener}" update="consonantWrapper" />
</p:selectOneMenu>
<h:panelGroup id="consonantWrapper" layout="block">
<p:selectOneMenu id="oneMenuConsonant" value="#{cc.attrs.bean.codigoProvincia}"
binding="#{cc.uiSelectOneConsonant}">
<f:selectItem itemLabel="Bbbb" itemValue="b" />
<f:selectItem itemLabel="Cccc" itemValue="c" />
<f:selectItem itemLabel="Dddd" itemValue="d" />
</p:selectOneMenu>
</h:panelGroup>
</cc:implementation>
Bean
public class Direccion implements Serializable {
private String codigoPais; /* with its getter and setter*/
private String codigoProvincia; /* with its getter and setter*/
}
XHTML
This is the way I use inside the xhtml pages: (The name of the controller changes depends on the current controller)
<sgnx:letter-example bean="#{controller.direccion}" />
The #Named beans
#Named
#ViewScoped
public class P001DatosNotificacionController
private Direccion direccion; /* with its getter and setter*/
#Named
#ViewScoped
public class P001GestionNotificacionesController
private Direccion direccion; /* with its getter and setter*/
#Named
#ViewScoped
public class P002BandejaProvisionalNotificacionesController
private Direccion direccion; /* with its getter and setter*/
After a few weeks I went back to the problem.
I decided to start again from scratch.
When I started to write the controller code and annotated it with #ViewScoped I realize about javax.faces.bean and javax.faces.view packages
And that was the mistake. I was using a wrong combination:
import javax.inject.Named;
import javax.faces.bean.ViewScoped;
So, the solution is as easy as using the proper combination of packages:
import javax.inject.Named;
import javax.faces.view.ViewScoped;
In these posts are the answer and the explanation:
#ViewScoped bean recreated on every postback request when using JSF 2.2
ManagedProperty in CDI #Named bean returns null
Inject CDI bean into JSF #ViewScoped bean

How to execute managed bean method on selectOneMenu change?

I have the following Managed Bean:
import javax.faces.bean.ManagedBean;
#ManagedBean
public class MyBean {
public void mostrarCentroSeleccionado() {
System.out.println("Value changed");
}
}
And inside my .xhtml file the following selectOneMenu:
<p:selectOneMenu value="#{MyBean.centros.idcentro}" >
<p:ajax event="change" listener="#{MyBean.mostrarCentroSeleccionado}" />
<f:selectItem itemLabel="Seleccione un centro" itemValue="" />
<f:selectItems value="#{MyBean.centros}" />
</p:selectOneMenu>
When I run that code I get the following exception:
javax.el.MethodNotFoundException
Thanks in advance
If Holger's solutions works out, its fine.
BUT: It is horrible to start start a Java Class Name with lower case letter. You can start with a capital letter and JSF will manage it for you, so you can still use
listener="#{myBean.mostrarCentroSeleccionado()}"
If this does not meet your requirements you can use
#ManagedBean(name = "myBean ")
Instead of myBean you can choose what ever you want.
The problem was in the tag:
<p:ajax listener="#{MyBean.function()}"/>
The function must have "()" becouse I´m not taking the event.

Primefaces with managedBeans always return null [duplicate]

This question already has answers here:
p:commandbutton action doesn't work inside p:dialog
(4 answers)
Closed 6 years ago.
I have a problem. I have a form
with inputs to be sent to a bean by , the thing is debugged, in the bean object is always null. Could you help me with this.
Here the code:
<h:form id="frmNuevo">
<p:dialog id="dialog" header="Añadir Presupuesto" widgetVar="dialogNuevo" resizable="true" width="500" height="500" showEffect="fade" hideEffect="explode" modal="true">
<p:growl id="growl" showDetail="true" sticky="true" />
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin: 0 auto;">
<h:outputText value="Diciembre:" />
<p:inputText value="#{presupuestoBean.presupuesto.diciembre}" required="true" maxlength="20" />
<p:commandButton value="Guardar" update=":form:cars, frmNuevo, growl, display" process="#this" actionListener="#{presupuestoBean.insertar}" oncomplete="dialogNuevo.hide()" image="icon-save" />
<p:commandButton value="Cancelar" update=":form:cars" oncomplete="dialogNuevo.hide()" style="margin-bottom: 20px;" image="icon-cancel" />
</h:panelGrid>
<p:separator/></p:dialog>
</h:form>
I tested with SessionScoped and RequestScoped and does not work, the strange thing is I have done other similar beans and if they work
ManagedBean:
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean(name = "presupuestoBean")
#RequestScoped
public class PresupuestoBean implements Serializable {
private TbPresupuesto presupuesto;
private List<TbPresupuesto> presupuestos;
private UploadedFile file;
private String destination = "C:\\temp\\";
public PresupuestoBean() {
presupuesto = new TbPresupuesto();
presupuestos = new ArrayList();
}
public TbPresupuesto getPresupuesto() {
return presupuesto;
}
public void setPresupuesto(TbPresupuesto presupuesto) {
this.presupuesto = presupuesto;
}
public void prepararInsertar() {
presupuesto = new TbPresupuesto();
presupuestos = new ArrayList();
}
public void insertar() {
PresupuestoDaoImpl presupuestoDao = new PresupuestoDaoImpl();
presupuesto.setPresupuestoId(presupuesto.getLinea().getLineaId());
presupuestoDao.insertar(presupuesto);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Se ha ingresado correctamente"));
presupuesto = new TbPresupuesto();
}
}
The form must go inside the dialog.
<p:dialog>
<h:form>
...
</h:form>
</p:dialog>
The generated HTML representation of the dialog component is namely during page load by JavaScript relocated to the end of <body> in order to improve cross browser compatibility of presenting a modal dialog.
With your current code, this thus means that the dialog will then not sit in a form anymore. So when you try to submit the input values inside the dialog, they will end up as nulls because there is no form in order to collect and send the input values to the server.
Further, you're only processing the submit button inside the command button.
<p:commandButton ... process="#this" />
Remove that attribute. It defaults to #form already, which is exactly what you want.

conditional rendered f:selectItem possible problems

I have a page with several h:selectOneMenu or p:selectOneMenu and I want to use the same page for editing and adding data.
When I will edit data I need f:selectItem. I know that this component doesn't have attribute rendered. And I read that I can use <c:if>.
Ok. For example, if I write
<p:selectOneMenu rendered="#{not empty bean.id}"
value="#{bean.selectedId}">
<c:if test="${editableBean != null}">
<f:selectItem itemLable="#{editableBean.name} itemValue=#{editableBean.id} />
</c:if>
<f:selectItems value="#{bean.listItems}" var="item"
itemLabel="#{item.name}" itemValue="#{item.id}"/>
</p:selectOneMenu>
Will it works without any problems in primefaces and with ajax listeners?
The easy solution (but with poor performance) will be to have a boolean editMode attribute in your managed bean to enable/disable the components. Basic example:
<p:selectOneMenu rendered="#{not empty bean.id}" disabled="#{bean.editMode}"
value="#{bean.selectedId}">
<f:selectItems value="#{bean.listItems}" var="item"
itemLabel="#{item.name}" itemValue="#{item.id}"/>
</p:selectOneMenu>
In your bean
#ManagedBean
#ViewScoped
public class Bean {
private int id;
private boolean editMode;
//other attributes...
//getters and setters...
#PostConstruct
public void init() {
//a way to know if the bean it's in edit mode
editMode = (id != 0);
}
}
This solution will have poor performance because every <p:selectOneMenu> will have to load all the data and then select the actual value, but it will do what you want. Another option will be to use this attribute for the rendered property of <p:selectOneMenu> and for an <h:inputText disabled="true" readonly="true" /> (or maybe <h:outputText />). Another basic sample:
<p:selectOneMenu rendered="#{not empty bean.id && not bean.editMode}"
value="#{bean.selectedId}">
<f:selectItems value="#{bean.listItems}" var="item"
itemLabel="#{item.name}" itemValue="#{item.id}"/>
</p:selectOneMenu>
<h:inputText rendered="#{bean.editMode}" value="{bean.selectedText}"
disabled="true" readonly="true" />

Resources