JSF - selectItems doesn't render list inside of list - java

I have the following facelet code which is failing:
<h:form>
<rich:select defaultLabel="Seleccionar región">
<f:selectItems value="#{StaticInfo.regiones}" var="region" itemValue="#{region.reg_Cod}" itemLabel="#{region.reg_Nombre}" />
<a4j:ajax event="change" render="provs" />
</rich:select>
<rich:select id="provs" defaultLabel="Seleccionar provincia">
<f:selectItems value="#{region.provincias}" var="prov" itemValue="#{prov.prov_Cod}" itemLabel="#{prov.prov_Nombre}" />
</rich:select>
</h:form>
Backing bean:
public class StaticInfoBean {
private ArrayList<Region> regiones;
public StaticInfoBean() {
try
{
RegionDAO regDao = new RegionDAO();
regDao.prepareConnection();
ProvinciaDAO provDao = new ProvinciaDAO();
provDao.setCon(regDao.getCon());
ComunaDAO comDao = new ComunaDAO();
comDao.setCon(regDao.getCon());
regiones = regDao.listaRegiones();
for(Region r : regiones)
{
regDao.findProvincias(r);
for(Provincia p : r.getProvincias())
{
provDao.findComunas(p);
for(Comuna c : p.getComunas())
{
comDao.findColegios(c);
}
}
}
regDao.getCon().close();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
public ArrayList<Region> getRegiones() {
return regiones;
}
public void setRegiones(ArrayList<Region> regiones) {
this.regiones = regiones;
}
public String toString() {
return regiones.toString();
}
}
Class Region:
public class Region {
private String Reg_Cod;
private String Reg_Nombre;
private ArrayList<Provincia> provincias;
//Getters and setters
The problem: The first rich:select tag works just fine. However the second one doesn't display any value. Not just that, but I'm working in NetBeans and it doesn't display the list of methods for class Provincia whenever I type "prov" in the EL.
Any help is appreciated.
EDIT: I edited my code and did the following:
<h:form>
<rich:select defaultLabel="Seleccionar región" value="#{StaticInfo.regionElegida}">
<f:selectItems value="#{StaticInfo.regiones}" var="region" itemValue="#{region.reg_Cod}" itemLabel="#{region.reg_Nombre}" />
<a4j:ajax event="click" render="provs" execute="#this" />
<a4j:ajax event="click" render="texto" execute="#this" />
</rich:select>
<h:outputText id="texto" value="#{StaticInfo.regionElegida.reg_Nombre}" />
<rich:select id="provs" defaultLabel="Seleccionar provincia" value="#{StaticInfo.provinciaElegida}" rendered="#{not empty StaticInfo.regionElegida}">
<f:selectItems value="#{StaticInfo.regionElegida.provincias}" var="prov" itemValue="#{prov.prov_Cod}" itemLabel="#{prov.prov_Nombre}" />
</rich:select>
</h:form>
What's surprising is that the outputText isn't being displayed! Why would this happen?

The variable region set in f:selectItems is only available inside its scope.
You have to bind each rich:select to a backing bean property.
So, you need to change your bean code, adding properties for the chosen region to the bean:
public class StaticInfoBean {
private ArrayList<Region> regiones;
private Region regionElegida;
private Provincia provinciaElegida; // <-- you'll probably want this too...
// ... getters and setters and your initialization code
// and you need something to find the real region object that
// used the reg_Cod value got from rich:select, for now you can try this:
public void updateRegionElegida(AjaxBehaviorEvent e){
// set the chosen region to regionElegida,
// or the poor man's converter
for (Region region : regiones){
if(regionElegida.getReg_Cod() == region.getReg_cod()) {
regionElegida = region;
}
}
}
}
and then change your XHTML to something like this:
<h:form>
<rich:select value="#{StaticInfo.regionElegida}"
defaultLabel="Seleccionar región">
<f:selectItems value="#{StaticInfo.regiones}" var="region"
itemValue="#{region.reg_Cod}" itemLabel="#{region.reg_Nombre}" />
<a4j:ajax event="change" render="provs"
listener="#{StaticInfo.updateRegionElegida}" />
</rich:select>
<rich:select id="provs" value="#{StaticInfo.provinciaElegida}"
defaultLabel="Seleccionar provincia">
<f:selectItems value="#{StaticInfo.regionElegida.provincias}" var="prov"
itemValue="#{prov.prov_Cod}" itemLabel="#{prov.prov_Nombre}" />
</rich:select>
</h:form>
Now, the professional way of doing that conversion thing would be to use a custom converter that can find the appropriate instance of a Region object based on the value of the expression itemValue used for its select widget. Check out this example from another question.
Note that rich:select only adds functionality to the default h:selectOneMenu, you would do good checking out its info page here at SO.

Related

<p: ​selectOneMenu /> <f: selectItems> do not appear

I'm developing a java application using jsf and put the <p: ​​selectOneMenu /> component primefaces in my project,But the <p: ​​selectOneMenu /> <f: selectItems> component items do not appear and <selectOneMenu /> has disappeared
UPDATE
<h:panelGroup layout="block" styleClass="tamanho">
<p>Tamanho:</p> <p:selectOneMenu id="tamanhos" value="#{tamanho.tamanho}" styleClass="tamanho" effect="fold" editable="true">
<f:selectItem itemValue="#{null}" itemLabel="-- select one --" />
<f:selectItems value="#{tamanho.tamanhos_roupas}" />
</p:selectOneMenu>
#ManagedBean(name="tamanho")
#RequestScoped
public class Tamanho {
private String tamanho;
private List<SelectItem> tamanhos_roupas; // +getter (no setter necessary)
#PostConstruct
public void init() {
tamanhos_roupas = new ArrayList<SelectItem>();
tamanhos_roupas.add(new SelectItem("PP", "PP"));
tamanhos_roupas.add(new SelectItem("P", "P"));
tamanhos_roupas.add(new SelectItem("M", "M"));
tamanhos_roupas.add(new SelectItem("G", "G"));
tamanhos_roupas.add(new SelectItem("GG", "GG"));
}
public String getTamanho() {
return tamanho;
}
public void setTamanho(String tamanho) {
this.tamanho = tamanho;
}
public List<SelectItem> getTamanhos_roupas() {
return tamanhos_roupas;
}
}
Look how the copier of the primefaces was, disappeared itens the <p:selectOneMenu/>
page
I'm assuming "#{tamanho.tamanhos_roupas}" is a list that has values in it already, so what you need to do is add 'var', 'itemValue' and 'itemLabel' in your selectItems tag.
The 'var' attribute is the name of the variable of your list elements in every iteration, 'itemValue' is what #{tamanho.tamanho} value will be after selecting an option and 'itemLabel' is what will the user read to identify that option.
<h:panelGroup layout="block" styleClass="tamanho">
<p>Tamanho:</p> <p:selectOneMenu id="tamanhos" value="#{tamanho.tamanho}"
styleClass="tamanho" effect="fold" editable="true">
<f:selectItem itemValue="#{null}" itemLabel="-- select one --" />
<f:selectItems value="#{tamanho.tamanhos_roupas}" var="tamanho"
itemValue="#{tamanho}" itemLabel="#{tamanho.stringNome}" />
</p:selectOneMenu>
See, the way your code is written you are only giving your SelectOneMenu the information you have items to iterate, but you never tell him what is the name and value of those items.

JSF Updating p:selectOneMenu from another p:selectOneListbox with Ajax

I've been trying to do something that would be really simple... yet it won't work.
I have 2 "p:selectOneMenu", so that the second one items depends on the chosen item in the first one. They both have their own methods in the bean to list their items.
What I wanted to do was when the first changes its value, update the another so that the component should reload the list considering the choosen object. But the ajax never happens, at least in debug the method in the Bean is never called again.
What is wrong? The code is something like...
Thanks!!! :)
<p:selectOneMenu value="#{itemBean.lotacao}">
<f:selectItem itemLabel="Choose one" />
<f:selectItems value="#{itemBean.listLotacoes()}"
var="lotacao"
itemLabel="#{lotacao.format()}" />
<p:ajax update="localizacaoPorLotacao" />
</p:selectOneMenu>
<p:selectOneMenu id="localizacaoPorLotacao"
value="#{itemBean.localizacao}">
<f:selectItem itemLabel="Choose one" />
<f:selectItems value="#{itemBean.listByLotacao(itemBean.lotacao)}" />
</p:selectOneMenu>
#ManagedBean
#SessionScoped
public class ItemBean {
// attributes, getters and setters here...
public List<Lotacao> listLotacoes() {
LotacaoService lotacaoService = new LotacaoService();
List<Lotacao> lotacoes = lotacaoService.getAll();
return lotacoes;
}
public List<Lotacao> listByLotacao(Lotacao lotacao) {
if (lotacao == null) {
return new ArrayList<Lotacao>();
}
String prefixo = lotacao.getCodigo().substring(0, 1);
LotacaoService lotacaoService = new LotacaoService();
List<Lotacao> lotacoes = lotacaoService.getByPrefix(prefixo);
return lotacoes;
}
}
Found it!
The lack of a converter to the class made the JSF don't trigger the setter.
After creating a converter and adding it to the OneMenu, the code worked just fine.
The final version is:
<p:selectOneMenu value="#{itemQuadroVagasBean.lotacao}"
converter="orgaoLotacaoCodigoConverter">
<p:ajax event="change"
update="localizacaoPorLotacao" />
<f:selectItem itemLabel="Selecione a lotação" />
<f:selectItems value="#{itemQuadroVagasBean.listarLotacoes()}"
var="lotacao"
itemLabel="#{lotacao.formatarLocalizacao()}" />
</p:selectOneMenu>
Maybe you need event:
<p:ajax update="localizacaoPorLotacao" event="change"/>

How to set a f:selectItem in a specific option after a p:commandButton action?

I have a javascript code that clears all the p:inputText (after a p:commandButton action) of the form. The problem is that the p:selectOneMenu still has the f:selectItem selected in the option it was selected. I need to put the values in the first f:selectItem of each p:selectOneMenu.
How to I do that? How can I clear the selected values?
The java script code:
<script type="text/javascript">
function limpiarForm()
{
document.getElementById("formularioAltas").reset();
}
</script>
formularioAltas is the form id.
The code of the p:commandButton:
<p:commandButton value="Guardar" action="#{altasBean.agregarRefaccion()}" oncomplete="limpiarForm()" />
And that code does not reset(I dont want to clear the values, I just want to put the first option selected) the values of the p:selectOneMenu
Here it is:
<h:outputText value="Estado de la refacción" />
<p:selectOneMenu value="#{altasBean.refaccion.estado}">
<f:selectItem itemLabel="..." itemValue="0" />
<f:selectItem itemLabel="Ok" itemValue="Ok" />
<f:selectItem itemLabel="Reparar" itemValue="Reparar" />
<f:selectItem itemLabel="Sospechoso" itemValue="Sospechoso" />
</p:selectOneMenu>
The bean:
private RefaccionBean refaccion = null;
/**
* Get the value of refaccion
*
* #return the value of refaccion
*/
public RefaccionBean getRefaccion() {
return refaccion;
}
/**
* Set the value of refaccion
*
* #param refaccion new value of refaccion
*/
public void setRefaccion(RefaccionBean refaccion) {
this.refaccion = refaccion;
}
public void agregarRefaccion() {
I did a lot of things here...
And after those things i clear the p:inputText with the javascript code
-> After that i want to set the values of the p:selectOneMenu in the fist f:selectItem
}
Josef's answer does lead you in the right direction, but since you shared some code, I will just use it in my answer.
First, make sure that your button calls your bean method and updates the selectOneMenu component after it's done. Although there's some ajax going on here, primefaces abstracts that for you.
<p:commandButton value="Guardar" action="#{altasBean.agregarRefaccion}" update="selectOneMenu" />
The update attribute is important as it will look for the component whose id matches whatever is specified there. So you need to give your selectOneMenu an id. If you need to update more than one component, you can add their ids to the update attribute separated by either space or comma.
<h:outputText value="Estado de la refacción" />
<p:selectOneMenu value="#{altasBean.refaccion.estado}" id="selectOneMenu">
<f:selectItem itemLabel="..." itemValue="0" />
<f:selectItem itemLabel="Ok" itemValue="Ok" />
<f:selectItem itemLabel="Reparar" itemValue="Reparar" />
<f:selectItem itemLabel="Sospechoso" itemValue="Sospechoso" />
</p:selectOneMenu>
Now it's just a matter of cleaning up your values inside your action method:
public void agregarRefaccion() {
//If you have other values to clean, clean them here
this.refaccion.estado="0"; //Matches the value for your first item
}
Now I'm not entirely sure if I follow you, but let me know if this helps you out at all. It's entirely JSF and I threw in some ajax. You can play around with your javascript still.
Front-end:
<p:inputText id="input" value="#{bean.value}" />
<p:commandButton value="button" action="#{bean.action}">
<f:ajax execute="input" render="output" />
</p:commandButton>
<p:selectOneMenu id="output" value="#{bean.placeValue}">
<f:selectItems value="#{bean.values}" />
</p:selectOneMenu>
Bean:
#ManagedBean
#RequestScoped
public class Bean {
private String value;
private List<String> values;
#EJB
private ValueService valueService;
#PostConstruct
public void init() {
values = valueService.list();
}
public void action() {
// ... Action taken
}
public String placeValue() {
// ... Validation and clear desired values
return value;
}
// ... (getters, setters, etc)
}

How to send/recieve data to/from bean function using JSF Richfaces AJAX?

I'm trying to get some code working in an XHTML/JSF/Spring application through which I send an ID to a bean function and expect a string in return. I haven't found an understandable tutorial on this nor any answered question here on SO.
XHTML:
<h:form>
<h:inputText id="inputId" value="#{npBean.idString}"/>
<a4j:commandButton value="get def" render="out">
<f:param value="#{npBean.idString}" name="id" />
<f:setPropertyActionListener target="#{npBean.definition}"/>
</a4j:commandButton>
<a4j:outputPanel id="out">
<h:outputText id="outputId" value="#{npBean.def}"
rendered="#{not empty npBean.def}"/>
</a4j:outputPanel>
</h:form>
Java:
public String getDefinition(int id)
{
def = this.getXService().getXData(id).getDefinition();
return def;
}
All values shown have their getters and setters in the bean.
What we basically do:
Map the value of the <h:inputText> component to a property (with getter/setter) in the managed-bean (which is called myBean)
By using the reRender attribute of the <a4j:commandButton> component, we point which component on the page to be re-rendered (refreshed) when the button is clicked.
When clicking on the button, the invokeService() method from the managedBean is executed and it updates the other property of the managedBean.
In the <h:panelGroup> below, we have several <h:outputText> components and with the rendered attribute we specify when a component has to be displayed on the page.
Exploring the managed-bean, the only thing that is required, are the accessors for the property, which holds the result from the service invoke.
Here's the *.xhtml sample:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<a4j:form>
<h:panelGrid columns="3">
<h:outputText value="String value:" />
<h:inputText value="#{myBean.value}" />
<a4j:commandButton value="Click" reRender="out">
<a4j:actionListener listener="#{myBean.invokeService}" />
</a4j:comandButton>
</h:panelGrid>
</a4j:form>
<rich:spacer height="7"/>
<br />
<h:panelGroup id="out">
<h:outputText value="Service returned: " rendered="#{not empty myBean.result}" />
<h:outputText value="#{myBean.result}" />
</h:panelGroup>
</ui:composition>
Managed-bean:
#ManagedBean(name = "myBean")
#SessionScoped //for example
public class MyBean {
private String value;
private String result;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getResult() {
return result;
}
public void invokeService(ActionEvent actionEvent) {
this.result = "Hello, " + value + "!";
}
}
As #Luiggi mentioned, the accessor methods MUST meet the following conventions (if we assume you have a private <some-type> property; in the managed-bean.)
public <some-type> getProperty {
return property;
}
public void setProperty(<some-type> property) {
this.property = property:
}
In order to learn how the RichFaces components work, combined with good code examples, I suggest you open this address and play around with the components.

rendering <h:panelGroup> by ajax in jsf

I've got this piece of code, which doesn't do exactly what I thought. I try to set property by Ajax and then re-render one component. My .xhtml looks like this
<h:form>
<h:commandButton value="Render!" >
<f:ajax render=":result" listener="#{eFindUser.findUser}" />
</h:commandButton>
</h:form>
<h:panelGroup id="result" layout="block" rendered="#{eFindUser.responseRendered}" >
This is some text that is supposed to be rendered later
</h:panelGroup>
the backing bean looks like this
#Named(value = "eFindUser")
#ViewScoped
public class EFindUserManagedBean implements Serializable{
private boolean responseRendered = false;
/**
* Creates a new instance of EFindUserManagedBean
*/
public EFindUserManagedBean() {
}
public void findUser(AjaxBehaviorEvent abe) {
responseRendered = !responseRendered;
System.out.println("finding..... ("+ responseRendered+")" + this);
}
public boolean isResponseRendered() {
return responseRendered;
}
public void setResponseRendered(boolean responseRendered) {
this.responseRendered = responseRendered;
}
}
When I re-click the button, the property is not changed. There is a message in serverlog, which says
INFO: finding..... (true)backingbeans.EFindUserManagedBean#5736b751
INFO: finding..... (true)backingbeans.EFindUserManagedBean#23959d6f
Clearly there is some issue with the managed bean as it is created every time there is a request even if it should be view-scoped.
What should I change so the panelgroup(id:"result") could change it's visibility? No richfaces or any other technology allowed.
Thank you very much for your answers
You can't render dynamically a JSF component that is not rendered all time. The object must exist in the DOM client side. When using rendered="false", the output is not generated server side.
Change your code like this :
<h:form>
<h:commandButton value="Render!" >
<f:ajax render=":result" listener="#{eFindUser.findUser}" />
</h:commandButton>
</h:form>
<h:panelGroup id="result">
<h:panelGroup layout="block" rendered="#{eFindUser.responseRendered}" >
This is some text that is supposed to be rendered later
</h:panelGroup>
</h:panelGroup>
With that, the DOM will always contain something with the id="result".
This works for me:
<ui:composition>
<h:form id="mainForm">
<h:commandButton value="Render!" action="#{eFindUser.findUser}">
<f:ajax event="action" render=":result" />
</h:commandButton>
</h:form>
<h:panelGroup id="result" layout="block" rendered="#{eFindUser.responseRendered}" >
This is some text that is supposed to be rendered later
</h:panelGroup>
</ui:composition>
Bean:
#ManagedBean
#ViewScoped
public class EFindUser implements Serializable{
private static final long serialVersionUID = -7106162864352727534L;
private boolean responseRendered = false;
public EFindUser() {
}
public void findUser() {
responseRendered = !responseRendered;
System.out.println("finding..... ("+ responseRendered+")" + this);
}
public boolean isResponseRendered() {
return responseRendered;
}
public void setResponseRendered(boolean responseRendered) {
this.responseRendered = responseRendered;
}
}
Take a look on JSF 2.0 + Ajax Hello World Example

Categories

Resources