I have a field that is rendered conditionally, based on a dropdown. All of that goes without problem, but when I submit the form of which the newly rendered component should be part of, it doesn't get submitted.
The code is fairly straightforward:
<h:form id="form">
<p:layout id="layout">
...
<p:layoutUnit id="layoutUnit">
...
<p:panel id="panel">
<p:outputPanel id="container1">
<p:selectOneMenu id="value1" value="#{bean.value1}">
<f:selectItem itemValue="1"/>
<f:selectItem itemValue="2"/>
<f:selectItem itemValue="3"/>
<f:selectItem itemValue="18"/>
<p:ajax event="change" update="container2"/>
</p:selectOneMenu>
</p:outputPanel>
<p:outputPanel id="container2">
<p:inputText id="value2"
value="#{bean.value2}"
rendered="#{bean.value1 eq 18}"
>
</p:inputText>
</p:outputPanel>
</panel>
<div id="buttons">
<p:commandButton id="commandButton" action="#{bean.save}" value="save" />
</div>
</layoutUnit>
</layout>
</form>
Tried possible solutions:
#ViewScoped of JSF is not usable, because it clashes with CDI
JSF Dynamic Rendered Component's Value becomes null when the form is submitted
conditionally rendered input component does not update value
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I can think of a few scenarios causing this behaviour:
'Rendered' seems to re-evaluate based on values in the backing bean,
rather than the new values given in the UI (if it defaults to 1, it is 1 again on submit, not 18). The component therefore
doesn't get submitted.
The added component isn't correctly added to
the form, and therefore not submitted.
?
Option 1 seems to be the most likely one, but could anyone point me in the right direction?
I work with WAS8.5 (so JSF2.0), Primefaces and CDI.
Using CDI's #ConversationScoped in addition to #Named is a solution. That scope works comparable to the #ViewScoped from JSF.
To get it working I've simply added code from the example here. So in short:
Bean.java
#Named
#ConversationScoped
public class Bean implements Serializable{
#Inject
private Conversation conversation;
Bean values, getters & setters
public void initConversation(){
if (!FacesContext.getCurrentInstance().isPostback() && conversation.isTransient()) {
conversation.begin();
}
}
public String endConversation(){
if(!conversation.isTransient()){
conversation.end();
}
}
public String navigateAwayFromScreen(){
endConversation();
}
}
beanOutput.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">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:event listener="#{bean.initConversation}" type="preRenderView"/>
<h:form id="form">
<p:layout id="layout">
...
<p:layoutUnit id="layoutUnit">
...
<p:panel id="panel">
<p:outputPanel id="container1">
<p:selectOneMenu id="value1" value="#{bean.value1}">
<f:selectItem itemValue="1"/>
<f:selectItem itemValue="2"/>
<f:selectItem itemValue="3"/>
<f:selectItem itemValue="18"/>
<p:ajax event="change" update="container2"/>
</p:selectOneMenu>
</p:outputPanel>
<p:outputPanel id="container2">
<p:inputText id="value2"
value="#{bean.value2}"
rendered="#{bean.value1 eq 18}"
>
</p:inputText>
</p:outputPanel>
</panel>
<div id="buttons">
<p:commandButton id="commandButton" action="#{bean.navigateAwayFromScreen}" value="Go away!" />
</div>
</layoutUnit>
</layout>
</form>
</html>
Now, a conversation gets started when you open the page (due to the initConversation being called from the top of beanOutput.xhtml), and ended when you click the button navigateAwayFromScreen.
(However, if you are able to work with JSF2.2, it should be possible to use the #ViewScoped in combination with CDI. (I say 'should': I am not in the situation to upgrade. But it may be useful to others to examine)).
Related
I found a problem while using the bootsfaces inputText with ajax.
I'm using JSF 2.2, Bootsfaces 0.8.1 and Primefaces 5.3.
I'm trying to enter a date value into the inputText field. As soon as I enter the last value for the date the inputText should trigger the change event. At this point I would like to use ajax for calling a bean method. The problem is, that my field loses focus as soon as I try to enter the last value and the method's never been invoked.
So I tried a bit with Primefaces and it almost works like I wanted. At this point I got different questions:
Why does my inputText field lose the focus while entering the last value? (Bootsfaces)
Why is the bean method never called after I lose the focus? (Bootsfaces)
Is it possible to invoke the bean method after the bean value has been set by the field? (Primefaces)
I added the code below, so maybe you can reproduce this behaviour.
test.xhtml - sample xhtml with both primefaces and bootsfaces fields
<?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">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:b="http://bootsfaces.net/ui"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<meta charset="UTF-8"/>
</h:head>
<h:body>
<h:form id="form">
<b:panel id="filterPanel" title="Filter properties" immediate="true" collapsed="false" collapsible="true">
<b:row>
<b:column span="12">
<b:inputText id="dateA" type="date" value="#{test.dateA}" immediate="true" class="form-control">
<f:ajax event="change" listener="#{test.searchA()}"/>
</b:inputText>
</b:column>
</b:row>
<b:row>
<b:column span="12">
<p:inputText id="dateB" type="date" value="#{test.dateB}" immediate="true" class="form-control">
<p:ajax event="change" listener="#{test.searchB()}"/>
</p:inputText>
</b:column>
</b:row>
</b:panel>
</h:form>
</h:body>
</html>
TestBean.java - my bean for setting the values and calling methods
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean(name = "test")
#ViewScoped
public class TestBean {
private String dateA;
private String dateB;
public void searchA() {
System.out.println("Search A");
}
public void searchB() {
System.out.println("Search B");
}
public String getDateA() {
return dateA;
}
public void setDateA(String dateA) {
this.dateA = dateA;
System.out.println(dateA);
}
public String getDateB() {
return dateB;
}
public void setDateB(String dateB) {
this.dateB = dateB;
System.out.println(dateB);
}
}
Please help me finding a solution or explain me what I'm doing wrong here.
Thanks
mweber
You've found a subtle difference between BootsFaces and PrimeFaces. I recommend you always define the values of process and update for the sake of clarity. In your case,
<b:inputText id="dateA" type="date" value="#{test.dateA}" immediate="true" class="form-control">
<f:ajax event="change" listener="#{test.searchA()}" render="#none"/>
</b:inputText>
makes the BootsFaces input field behave exactly like its PrimeFaces counterpart.
The default values of update and process are different. Since BootsFaces 0.8.5, the default values are:
process="#form" for <b:commandButton /> and <b:commandLink />
process="#this" for every other BootsFaces component
update="#form" for every BootsFaces component
According to Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes, the PrimeFaces default values are:
For the sake of convenience, here's my version of the XHTML file:
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
xmlns:b="http://bootsfaces.net/ui"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<meta charset="UTF-8"/>
</h:head>
<h:body>
<h:form id="form">
<b:panel id="filterPanel" title="Filter properties" immediate="true" collapsed="false" collapsible="true">
<b:row>
<b:column span="12">
<b:inputText id="dateA" type="date" value="#{test.dateA}" immediate="true" class="form-control">
<f:ajax event="change" listener="#{test.searchA()}" render="#none"/>
</b:inputText>
</b:column>
</b:row>
<b:row>
<b:column span="12">
<p:inputText id="dateB" type="date" value="#{test.dateB}" immediate="true" class="form-control">
<p:ajax event="change" listener="#{test.searchB()}"/>
</p:inputText>
</b:column>
</b:row>
</b:panel>
</h:form>
</h:body>
</html>
I've tested it with BootsFaces 0.8.5.
I am trying to display all available FontAwesome icons in a p:selectOneMenu component.
The renderer is supposed to render the icon first, then display the icon's name. A similar example can be found here but is implemented especially for BootStrap: https://mjolnic.com/fontawesome-iconpicker/
----------------------------------
|- ICON - | Icon name |
----------------------------------
Unfortunately, the custom columns just do not get rendered. The p:selectOneMenuappears but is rendered as by default.
My picker xhtml page looks as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html 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:p="http://primefaces.org/ui">
<h:head></h:head>
<body>
<p:panel>
<h:form id="iconPicker">
<p:selectOneMenu id="iconSelectOneMenu"
value="#{iconController.availableIconStrings}">
<f:selectItem itemLabel="Choose icon"
noSelectionOption="true" />
<f:selectItems
value="#{categoryController.availableIconStrings}"
var="_icon" itemValue="#{_icon}"
itemLabel="#{_icon}" />
<p:column>
<p:button id="iconButton" icon="#{_icon}" />
</p:column>
<p:column>
<h:outputText value="#{_icon}" />
</p:column>
</p:selectOneMenu>
</h:form>
</p:panel>
</body>
</html>
The IconController class:
public class IconController implements Serializable {
private List<String> availableIconStrings;
public IconController() { }
#PostConstruct
public void init() {
availableIconStrings = new ArrayList<>();
availableIconStrings.addAll(Arrays
.asList("fa-adjust,fa-adn,fa-align-center,fa-align-justify,fa-align-left,"
+ "fa-align-right,fa-ambulance,fa-anchor,fa-android,fa-angellist,"
+ "fa-angle-double-down,fa-angle-double-left,fa-angle-double-right,"
+ "fa-angle-double-up,fa-angle-down,fa-angle-left,fa-angle-right"
// Shortened list
.split(",")));
}
public List<String> getAvailableIconStrings() {
return availableIconStrings;
}
public void setAvailableIconStrings(List<String> availableIconStrings) {
this.availableIconStrings = availableIconStrings;
}
}
As you can see, I am trying to render the icon using a p:button. Do I understand it correctly that I need a PrimeFaces component that is able to display icons (e.g. p:button, p:commandButton, p:commandLink) to achieve my goal?
Any help is appreciated. Thanks a lot.
P.S.: Using PrimeFaces 5.3, JSF 2.2 and Mojarra on WildFly 9.0.2
For simplicity and re-usability, I decided to wrap the Strings in an Icon class and not to follow implement a different Renderer class as suggested by BalusC in the workaround (https://stackoverflow.com/a/32740430/2118909).
public class Icon {
private String fontIconName;
public Icon(String fontIconName) {
this.fontIconName = fontIconName;
}
public String getFontIconName() {
return fontIconName;
}
public void setFontIconName(String fontIconName) {
this.fontIconName = fontIconName;
}
}
The JSF page looks as follows:
<p:selectOneMenu id="iconSelectOneMenu"
value="#{iconController.selectedIcon}" var="_icon" converter="#{iconConverter}">
<f:selectItem itemLabel="Choose icon"
noSelectionOption="true" />
<f:selectItems
value="#{categoryController.availableIcons}" itemValue="#{_icon}"
itemLabel="#{_icon.fontIconName}" />
<p:column>
<i class="fa fa-fw #{_icon.fontIconName}"/>
</p:column>
<p:column>
<h:outputText value="#{_icon.fontIconName}" />
</p:column>
</p:selectOneMenu>
Please also note the following:
#{iconController.selectedIcon} now refers to an instance of the Icon class
#{iconController.availableIcons} now refers to a List<Icon> instance
I have added a Converter for the Icon class.
The icon is now rendered in an <i/> element.
Please also note the importance and role of the customContent variable in the SelectOneMenuRenderer.encodePanel(...) method which indicates that you need a var value on the p:selectOneMenu directly (not in the <f:selectItems/> element!) or the renderer will not recognize that there is custom content as it does not evaluate the <f:selectItems/> var attribute.
Two things:
In order to use p:column in combination with p:selectOneMenu you need to declare the var attribute on the p:selectOneMenu and reference it within your p:column. An example can be found on the PrimeFaces showcase.
So your code should be:
<p:selectOneMenu id="iconSelectOneMenu"
value="#{iconController.availableIconStrings}" var="ic">
<f:selectItem itemLabel="Choose icon"
noSelectionOption="true" />
<f:selectItems
value="#{categoryController.availableIconStrings}"
var="_icon" itemValue="#{_icon}"
itemLabel="#{_icon}" />
<p:column>
<p:button id="iconButton" icon="#{ic}" />
</p:column>
<p:column>
<h:outputText value="#{ic}" />
</p:column>
</p:selectOneMenu>
Now, You are facing a bug because you are using a List<String> as explained on this SO question:
So, if the item value is an instance of String, custom content via p:column is totally ignored.
You can find a workaround in the same post: https://stackoverflow.com/a/32740430/2118909
Use inputGroup
<div class="ui-inputgroup">
<div class="ui-inputgroup-addon"><i class="pi pi-user"></i></div>
<p:inputText placeholder="Username"/>
</div>
https://www.primefaces.org/showcase/ui/input/inputGroup.xhtml
See https://www.primefaces.org/showcase/ui/input/oneMenu.xhtml for an example:
<p:outputLabel value="Icons" />
<h:panelGroup styleClass="ui-inputgroup">
<h:panelGroup id="icon" styleClass="ui-inputgroup-addon">
<i class="pi pi-#{selectOneMenuView.icon}"/>
</h:panelGroup>
<p:selectOneMenu value="#{selectOneMenuView.icon}" var="item">
<f:selectItems value="#{['flag','wallet','map','link']}" var="item" itemLabel="#{item}"
itemValue="#{item}" />
<p:column><i class="pi pi-#{item}" /> #{item} </p:column>
<p:ajax update="#parent:#parent:icon" />
</p:selectOneMenu>
</h:panelGroup>
It is a workaround, yes, but it's the best option currently.
See also:
https://github.com/primefaces/primefaces/issues/6140
I have a Jsf page with a fragment with <p:selectOneMenu/> (Prime faces) and an Ajax associated with it. It have the default select item "--- Select One ---" and others items that were created dynamically.
This field is required, so if users submit the form without select, the page show a error message.
The problem occurs when I select one of this others options and go back selecting "--- Select One ---" again. Then the page shows the required field message, even before I submit the form. I try different ways of immediate in <p:ajax> and <p:selectOneMenu> tags but none of them has the expected behavior.
The <p:messages> is declared as below:
-- list.xhtml
<p:messages id="messages" autoUpdate="true" closable="true" escape="false" />
<.... include fragment.xhtml ....>
And the fragment:
-- fragment.xhtml
<p:selectOneMenu id="selectTipoCarro"
value="#{carroBean.carro.tipoCarroEnum}"
required="true">
<f:selectItems value="#{carroBean.listaSelectItemTipoCarroInclusao}" />
<p:ajax update="outputInicioVigenciaWrapper outputLabelCalendarInicioVigenciaWrapper"
listener="#{carroBean.aoMudarTipoCarro}" />
</p:selectOneMenu>
<h:panelGroup id="outputLabelCalendarInicioVigenciaWrapper">
<h:outputLabel id="outputLabelCalendarInicioVigencia"
rendered="#{carroBean.edicaoDataInicioVigenciaDisponivel}"
for="calendarInicioVigencia">
<span>*
#{labels['carro.inicio.vigencia']}: </span>
<p:calendar id="calendarInicioVigencia"
value="#{carroBean.carro.dataInicioVigencia}"
showOn="button"
pattern="dd/MM/yyyy" mask="true"
required="true"/>
</h:outputLabel>
</h:panelGroup>
<h:panelGroup id="outputInicioVigenciaWrapper">
<h:outputLabel for="outputInicioVigencia"
rendered="#{not carroBean.edicaoDataInicioVigenciaDisponivel}">
<span aria-live="polite">
<h:outputText id="outputInicioVigencia"
value="#{carroBean.carro.dataInicioVigencia}"
styleClass="dataFormat"
</h:outputText>
</span>
</h:outputLabel>
</h:panelGroup>
private SelectItem obterSelectItemSelecione() {
SelectItem selectItem = new SelectItem("", "-- Select One --");
return selectItem;
}
private void preencherListaSelectItemTipoCarro(List<SelectItem> select, TipoCarroEnum[] tiposCarrosConsiderados) {
select.clear();
select.add(obterSelectItemSelecione());
for (TipoCarroEnum tipoCarro : tiposCarrosConsiderados) {
select.add(new SelectItem(tipoCarro, tipoCarro.getNome()));
}
}
public void aoMudarTipoCarro() {
getCarro().setDataInicioVigencia(carroService.obterProximaDataInicioVigenciaDisponivel(getCarro().getTipoCarroEnum()));
}
That's the expected behaviour. When adding a p:ajax tag to your p:selectOneMenu you make the value be processed everytime the user changes the input, so it will be validated and rejected if you mark it as required. My favourite workaround for this cases is to include a request param in the button to submit the whole form and check for it in the required attribute. That's it:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:comp="http://java.sun.com/jsf/composite/comp"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head />
<h:body>
<h:form>
<p:messages autoUpdate="true" />
<p:selectOneMenu value="#{val}"
required="#{param['validate']}">
<p:ajax event="change" />
<f:selectItem itemLabel="None" noSelectionOption="true" />
<f:selectItem itemLabel="val1" itemValue="val1" />
</p:selectOneMenu>
<p:commandButton value="Submit" ajax="false">
<f:param name="validate" value="true" />
</p:commandButton>
</h:form>
</h:body>
</html>
See also:
Conditionally skip JSF validation but perform model updates
Explanation
This happens because you have a p:messages component with autoUpdate set to true and you have attached p:ajax to your selectOneMenu so anytime your value changes, p:messages is updated. Therefore, due to the use of required="true" an error messages is shown as soon as you have selected "--- Select One ---".
Solution
Add ignoreAutoUpdate="true" to your p:ajax or
Remove autoUpdate="true" if not necessary
This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 7 years ago.
I am using Primefaces 3.4.2.
I have the following in my JSF page
<p:selectOneMenu id="emp" value="#{mymb.emp.employeeName}"
valueChangeListener="#{mymb.handleChange}"
required="true"
style="width: 150px;">
<f:selectItem noSelectionOption="true"
itemLabel="Please Select"/>
<f:selectItems value="#{mymb.employeeList}" var="emp"
itemLabel="#{emp.employeeName}"
itemValue="#{emp.employeeNumber}"/>
<p:ajax update="sublist"/>
</p:selectOneMenu>
and in ManagedBean
public void handleChange(ValueChangeEvent event){
System.out.println("here "+event.getNewValue());
}
The problem is valueChangeListener is not firing, i.e. handleChange method is not getting invoked. I tried with the following, but it is not working either.
<p:ajax update="sublist" listener="#{mymb.handleChange}" />
Separate JSF page:
<ui:composition template="/templates/layout.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:define name="content">
<h:head>
</h:head>
<h:body>
<h:form id="form">
<p:panelGrid columns="6">
<h:outputLabel value="Employees" for="employees" />
<p:selectOneMenu id="employees"
value="#{mymb.employeesList}"
required="true">
<f:selectItems value="#{mymb.employeesList}" var="emp"
itemLabel="#{emp.employeeName}" />
<p:ajax listener="#{mymb.handleChange}" />
</p:selectOneMenu>
</p:panelGrid>
</h:form>
</h:body>
</ui:define>
</ui:composition>
If you want to use valueChangeListener, you need to submit the form every time a new option is chosen. Something like this:
<p:selectOneMenu value="#{mymb.employee}" onchange="submit()"
valueChangeListener="#{mymb.handleChange}" >
<f:selectItems value="#{mymb.employeesList}" var="emp"
itemLabel="#{emp.employeeName}" itemValue="#{emp.employeeID}" />
</p:selectOneMenu>
public void handleChange(ValueChangeEvent event){
System.out.println("New value: " + event.getNewValue());
}
Or else, if you want to use <p:ajax>, it should look like this:
<p:selectOneMenu value="#{mymb.employee}" >
<p:ajax listener="#{mymb.handleChange}" />
<f:selectItems value="#{mymb.employeesList}" var="emp"
itemLabel="#{emp.employeeName}" itemValue="#{emp.employeeID}" />
</p:selectOneMenu>
private String employeeID;
public void handleChange(){
System.out.println("New value: " + employee);
}
One thing to note is that in your example code, I saw that the value attribute of your <p:selectOneMenu> is #{mymb.employeesList} which is the same as the value of <f:selectItems>. The value of your <p:selectOneMenu> should be similar to my examples above which point to a single employee, not a list of employees.
The valueChangeListener is only necessary, if you are interested in both the old and the new value.
If you are only interested in the new value, the use of <p:ajax> or <f:ajax> is the better choice.
There are several possible reasons, why the ajax call won't work. First you should change the method signature of the handler method: drop the parameter. Then you can access your managed bean variable directly:
public void handleChange(){
System.out.println("here "+ getEmp().getEmployeeName());
}
At the time, the listener is called, the new value is already set. (Note that I implicitly assume that the el expression mymb.emp.employeeName is correctly backed by the corresponding getter/setter methods.)
Another solution is to mix valueChangeListener, ajax and process:
<p:selectManyCheckbox id="employees" value="#{employees}" columns="1" layout="grid" valueChangeListener="#{mybean.fireSelection}" >
<f:selectItems var="employee" value="#{employeesSI}" />
<p:ajax event="valueChange" immediate="true" process="#this"/>
</p:selectManyCheckbox>
Method in mybean is just :
public void fireSelection(ValueChangeEvent event) {
log.debug("New: "+event.getNewValue()+", Old: "+event.getOldValue());
}
Like this, valueChangeEvent is very light !
PS: Works fine with PrimeFaces 5.0
<p:ajax listener="#{my.handleChange}" update="id of component that need to be rerender after change" process="#this" />
import javax.faces.component.UIOutput;
import javax.faces.event.AjaxBehaviorEvent;
public void handleChange(AjaxBehaviorEvent vce){
String name= (String) ((UIOutput) vce.getSource()).getValue();
}
All can be defined as in f:ajax attiributes.
i.e.
<p:selectOneMenu id="employees" value="#{mymb.employeesList}" required="true">
<f:selectItems value="#{mymb.employeesList}" var="emp" itemLabel="#{emp.employeeName}" />
<f:ajax event="valueChange" listener="#{mymb.handleChange}" execute="#this" render="#all" />
</p:selectOneMenu>
event: it can be normal DOM Events like click, or valueChange
execute: This is a space separated list of client ids of components that will participate in the "execute" portion of the Request Processing Lifecycle.
render: The clientIds of components that will participate in the "render" portion of the Request Processing Lifecycle. After action done, you can define which components should be refresh. Id, IdList or these keywords can be added: #this, #form, #all, #none.
You can reache the whole attribute list by following link:
http://docs.oracle.com/javaee/6/javaserverfaces/2.1/docs/vdldocs/facelets/f/ajax.html
Try using p:ajax with event attribute,
My problem were that we were using spring securyty, and the previous page doesn't call the page using faces-redirect=true, then the page show a java warning, and the control doesn't fire the change event.
Solution:
The previous page must call the page using, faces-redirect=true
this works for me:
It can be used inside the dialog, but the dialog canĀ“t be inside any componet such as panels, accordion, etc.
I have the following situation that I would like to handle in JSF. My form consists of family information (name/address/phone) and then children information. Since a family can have more then one child, I need to be able to allow the person to click "add more children" and another child "section" will appear.
Here is a simple test case I've thrown together.
Backing Bean. A family has a list of children.
#ViewScoped
#ManagedBean
public class TestBackingBean implements Serializable {
private Family f = new Family();
private Child childToRemove;
public TestBackingBean() {
f.addChild(new Child());
}
public Family getFamily() {
return f;
}
public void setChildToRemove(Child childToRemove) {
this.childToRemove = childToRemove;
}
public TimeZone getTimezone() {
return TimeZone.getDefault();
}
public List<Child> getChildren() {
return f.getChildrenAsList();
}
public Child getChildToRemove() {
return childToRemove;
}
public void addChild() {
f.addChild(new Child());
}
public void removeChild() {
f.removeChild(childToRemove);
}
}
Here is the JSF page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><ui:insert name="title" />
</title>
<link rel="stylesheet" type="text/css" href="/hcbb/css/main.css" />
</h:head>
<h:body>
<h:form>
<h:panelGroup id="parentSection">
<h:outputLabel value="Parent Name" for="parent_firstName" />
<h:inputText id="parent_firstName" requiredMessage="Required"
immediate="true" label="Parent First Name"
value="#{testBackingBean.family.firstName}">
<f:validateRequired />
</h:inputText>
<rich:message id="parent_firstNameMessage" for="parent_firstName" />
</h:panelGroup>
<h:panelGroup id="childrenSection">
<h:dataTable value="#{testBackingBean.children}" var="child">
<h:column>
<h:panelGrid id="childPanel" columns="3"
style="border:1px solid brown; padding: 5px; margin-bottom:5px; width: 600px;">
<h:outputText id="childTitle" value="Child"
style="font-weight: bold;" />
<h:outputText id="spacer" />
<a4j:commandButton id="removeBtn"
action="#{testBackingBean.removeChild}" immediate="true"
value="Remove Child" render="childrenSection"
style="float:right;" title="Remove">
<f:setPropertyActionListener
target="#{testBackingBean.childToRemove}" value="#{child}" />
</a4j:commandButton>
<h:outputLabel id="child_firstNameLbl" value="First Name" />
<h:inputText id="child_firstName" requiredMessage="Required"
immediate="true" label="Child First Name"
value="#{child.firstName}">
<f:validateRequired />
</h:inputText>
<rich:message id="child_firstNameMessage" for="child_firstName" />
<h:outputLabel id="child_lastNameLbl" value="Last Name" />
<h:inputText id="child_lastName" requiredMessage="Required"
immediate="true" label="Child Last Name"
value="#{child.lastName}">
<f:validateRequired />
</h:inputText>
<rich:message id="child_lastNameMessage" for="child_lastName" />
<h:outputLabel id="child_dobLbl" value="Birth Date" />
<h:inputText id="child_dob" label="Child Birth Date"
immediate="true" requiredMessage="Required"
value="#{child.dateOfBirth}">
<f:convertDateTime id="dobConverter" pattern="MM/dd/yyyy"
timeZone="#{testBackingBean.timezone}" />
<f:validateRequired />
</h:inputText>
<rich:message id="child_dobNameMessage" for="child_dob" />
</h:panelGrid>
</h:column>
</h:dataTable>
<a4j:commandLink id="addChildBtn" immediate="true"
render="childrenSection" action="#{testBackingBean.addChild}"
value="Add Another Child">
</a4j:commandLink>
</h:panelGroup>
</h:form>
</h:body>
</html>
The issue is the saving of the values when adding/removing child sections. If you enter parent name and then child name and date of birth and then click add the fields for the child you just added will disappear? I would have thought that immediate=true on the button and the fields will get them through.
The problem is add a parent first name, enter child info and click the add another child button and the child information you just entered will be erased.
Any suggestions on how I might be able to make this all work. Seems like a fairly simple and somewhat standard use case.
Thanks!
It looks fine at the first glance. The problem symptoms boils down that the f.getChildrenAsList() doesn't return a list with the new child while JSF is about to apply request values. Perhaps that method is re-fetching the list from DB again upon submit? Add a breakpoint to investigate its retun value. Or perhaps the view scope failed and caused the bean to be reconstructed? Add a breakpoint to the bean's constructor. It should not be reconstructed when you're submitting the form against the same view.
As to using the immediate attribute, all your usage of them is entirely superfluous. Just remove them. To understand its use better, get yourself through the Debug JSF lifecycle article (true, it's JSF 1.2 targeted, but the principles are the same for JSF2) and then read particularly this summary:
Okay, when should I use the immediate attribute?
If it isn't entirely clear yet, here's a summary, complete with real world use examples when they may be beneficial:
If set in UIInput(s) only, the process validations phase will be taken place in apply request values phase instead. Use this to prioritize validation for the UIInput component(s) in question. When validation/conversion fails for any of them, the non-immediate components won't be validated/converted.
If set in UICommand only, the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s). Use this to skip the entire processing of the form. E.g. "Cancel" or "Back" button.
If set in both UIInput and UICommand components, the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s) which does not have this attribute set. Use this to skip the processing of the entire form expect for certain fields (with immediate). E.g. "Password forgotten" button in a login form with a required but non-immediate password field.