I have a JSF composite component which includes as a root an h:form. The form has many components among of which are selectOneMenu and a h:inputFile. When I set enctype="multipart/form-data" on the form, the valuechangelistener of the selectOneMenu is invoked ONLY for two value-changing events. Later, however I interact with the menu, the value change listener is not invoked at all. However, if I remove the enctype="multipart/form-data" every thing works fine. I have to keep enctype="multipart/form-data" because I have a file upload component.
Here is my Bean :
#Model
#ViewScoped
public class TransactionBean implements Serializable {
private Part inReceiptFilePart;
/*setter and getter*/
private TransactionType transactionType;
/*setter and getter*/
private final TransactionType transTypeList[] = {
TransactionType.COMPLETE,TransactionType.TECHNICAL,TransactionType.SUBMUNICIPALITY_TECHNICAL, TransactionType.COMPLAINT, TransactionType.FOLLOWUP_COUNCIL, TransactionType.FOLLOWUP_MANAGEMENT
};
public TransactionType[] getTransTypeList() {
return transTypeList;
}
public void transactionTypeChanged(ValueChangeEvent event) {
... /// some code
}
}
And here is the JSF composite component :
<h:form id="entryForm" enctype="multipart/form-data">
<p:selectOneMenu id="transType" value="#{transactionBean.transactionType}" style="direction: ltr" valueChangeListener="#{transactionBean.transactionTypeChanged}">
<f:ajax execute="transType" render="#form" > </f:ajax>
<f:selectItems value="#{transactionBean.transTypeList}" var="tt" itemLabel="#{tt.arName}">
</f:selectItems>
</p:selectOneMenu>
<h:inputFile value="#{transactionBean.inReceiptFilePart}" > </h:inputFile>
<p:commandButton id="insertTrans" value="أدخل المعاملة" action="#{transactionBean.insertTransaction}" ajax="false">
</p:commandButton>
</h:form>
The environment is JSF 2.2, Glassfish 4.0 and primefaces 3.5.
Please help me. I am stuck for three days on this problem.
Thanks
This is very strange behavior!
Try changing valueChangeListener event to an AJAX call.
<p:selectOneMenu id="transType" value="#{transactionBean.transactionType}" style="direction: ltr" >
<p:ajax event="change" partialSubmit="true" update="#form" listener="#{transactionBean.transactionTypeChanged}"/>
<f:selectItems value="#{transactionBean.transTypeList}" var="tt" itemLabel="#{tt.arName}" />
</p:selectOneMenu>
Primefaces's AJAX component is behavior component that extends JSF AJAX.
It adds and manages new events (e.g. valueChange); it also reattach javascript events to DOM element automatically.
Your case is that jsf's ajax does not rebind the valueChange Listener to "transType" selectOneMenu when the form is mutipart! (It's very strange, because the behavior should be the same of those ajax event, weather the form is mutipart or www-form-encoded!
Related
I'm using PrimeFaces' p:fieldset component and I want to control, from my bean, either or not it's collapsed. I expected the collpased property to do this job, but this is not working.
On the other hand, a "binding" seems to correctly mirror the component's state:
My Bean
#Named
#RequestScoped
public class TestBean {
//with get/set
private boolean collapsed;
//with get/set
private Fieldset fieldset;
}
My page:
<h:form>
<p:fieldset
id="togglebleFieldset"
legend="Toggleable Fieldset"
toggleable="true"
binding="#{testBean.fieldset}"
collapsed="#{testBean.collapsed}">
fieldset content
<p:ajax event="toggle" update="#form"/>
</p:fieldset>
<h:outputText value="Value is never updated: #{testBean.collapsed}" />
<br/><h:outputText value="Binding correctly reflects the state: #{testBean.fieldset.collapsed}" />
</h:form>
For reasons beyond the scope of this question, using the binding solution will be a little bit more complicated to me.
Why isn't #{testBean.collapsed} being update with the component's collapsed value?
(Using versions 6.0 and 6.2 of PrimeFaces)
I'm using JSF 2.2.8 and primefaces 6.0, and i have a selectCheckBoxMenu i want to retrieve the selected values in my bean.
The selectCheckboxMenu is filled from the database but when i select the attributes and I save nothing happens it does not call the save function
Here is my selectCheckBoxMenu
<p:outputLabel for="ressource" value="Ressource"/>
<h:panelGroup >
<p:selectCheckboxMenu id="ressource" label="Ressource" value="#{affectationBean.selectedRessource}" multiple="true">
<f:selectItems value="#{affectationBean.ressources}" var="r" itemLabel="#{r.nom}" itemValue="r.idt_ressource" />
</p:selectCheckboxMenu>
</h:panelGroup>
<p:commandButton icon="ui-icon-save" actionListener="#{affectationBean.save}" value="Save" update="#affectation" ajax="false" style="display:inline-block;margin-top:5px"/>
Here is the the declaration of the selectedRessource and the actionListener save
private Long [] selectedRessource;
// Getters setters and Construct
public void save(){
for(int i=0 ;i<selectedRessource.length;i++){
system.out.println("id ===> " + selectedRessource[i]);
}
My suggestion would be:
First make sure everything is inside the h:form tag.
don't need to multiple = true as this tag does not take this attribute
i tested with below modification and got the selected multiple value in my bean. The only difference is i am using same value for itemLabel and itemValue but in your case it is object. i am using primefaces 6 also and dont even need to change actionListner to action. It is working as it is.sample xhtml
sample ResourceBean.java
<p:outputLabel for="ressource" value="Ressource"/>
<h:panelGroup >
<p:selectCheckboxMenu id="ressource" label="Ressource" value="#{resourceBean.selectedRessource}">
<f:selectItems value="#{resourceBean.ressources}" var="r" itemLabel="#{r}" itemValue="#{r}" />
</p:selectCheckboxMenu>
</h:panelGroup>
<p:commandButton icon="ui-icon-save" actionListener="#{resourceBean.save}" value="Save" ajax="false" style="display:inline-block;margin-top:5px"/>
The problem is in your p:commandButton, you have 3 options
change your method:
public void save(ActionEvent actionEvent){...}
change your action listener value:
actionListener="#{affectationBean.save()}"
or change your button to use action
action="#{affectationBean.save}"
DISCLAIMER: This is a workaround. It is not intended to be a permanent solution but will allow you to use selectCheckboxMenu and keep working.
There is an issue with this component that prevents it from passing values to the backing bean upon submit.
For some reason the array that should contain the selected values gets cleared out upon submit. Therefore I made an extra array that I did not declare in the tag, and updated in on every change event. Then on submit the values were still there. See below:
BackingBean.java
private String[] sCodes;
private String[] sCodes2; //extra array, not in form.xhtml
public void updateCodes()
{
sCodes2 = sCodes; //keeps the values in the other array
}
public void doSend() throws IOException
{
log.trace("selected codes: {} selected codes2 length: {}", sCodes.length, sCodes2.length);
}
form.xhtml
<p:selectCheckboxMenu id="codeCtl" value="#{bean.SCodes}" label="Codes" filter="true" filterMatchMode="startsWith" panelStyle="width:250px">
<f:selectItems value="#{bean.menuCodes}" />
<p:ajax event="change" listener="#{bean.updateCodes()}" />
</p:selectCheckboxMenu>
<p:commandButton value="submit" actionListener="#{bean.doSend}" id="ctlSubmit" update="appform"/>
I am trying to log the number of the button clicks.
1. Should log the number of clicks though the form is invalid. The field value1 in the form is integer. So, It shall also consider conversion errors.
2. Action to be done at backing bean
I have tried with listener on ajax.
<h:form id="form">
<h:inputText id="in" name="in" value="#{listenBean.value1}" autocomplete="off">
</h:inputText>
<h:commandButton value="Click Me" action="#{listenBean.save}">
<f:ajax execute="#form" render="#form message eventcount" />
</h:commandButton>
<h:message for="in"/>
Button Clicks: <h:outputText id="eventcount" value="#{listenBean.eventCount}"/>
</h:form>
Bean
public void eventCount(AjaxBehaviorEvent event) {
//increment the counter
}
public void save() {
//save
}
Issues:
The listener method is not called when the conversion errors on input field binded to integer at bean. I enter the value as "some text". During thsi time listener is not called.
Version: Mojaraa 2.2.8
Is this the correct way of doing. Am I doing any mistake.
Can some one help me.
The <h:outputText value> doesn't represent a method expression which should reference a bean (listener) method. It represents a value expression which should reference a bean property which will then be outputted as (escaped) text to the response.
Your best bet is to hook on preRenderView event of the component and check if the current request represents a postback request.
<h:form id="form">
<h:commandButton ...>
<f:ajax execute="#form" render="#form" />
</h:commandButton>
Button Clicks:
<h:outputText id="eventcount" value="#{listenBean.eventCount}">
<f:event type="preRenderView" listener="#{listenBean.incrementEventCount}" />
</h:outputText>
</h:form>
private int eventCount;
public void incrementEventCount(ComponentSystemEvent event) {
if (FacesContext.getCurrentInstance().isPostback()) {
eventCount++;
}
}
public int getEventCount() {
return eventCount;
}
Note that render="#form" covers the entire form already, so there's no need of specifying individual components inside the very same form. In case you've another ajax action inside the same form for which you'd like to not count the event, then make sure that render="..." is specific enough that it doesn't cover the eventcount component.
I am seeing different behaviors of and in a page containing multiple forms.
Here is my backing bean:
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class MultiFormBean
{
String inputText1 = "";
String inputText2 = "";
#PostConstruct
public void initializeBean(){
System.out.println("PostConstruct Called ------------------");
}
public String getInputText1()
{
return inputText1;
}
public void setInputText1(String inputText1)
{
this.inputText1 = inputText1;
}
public String getInputText2()
{
return inputText2;
}
public void setInputText2(String inputText2)
{
this.inputText2 = inputText2;
}
public void doSubmit1() {
inputText2 = inputText1;
}
public void doSubmit2() {
inputText1 = inputText2;
}
}
When i use the following xhtml , clicking Submit1 and Submit2 any number of times won't call #PostConstruct more than once:
<h:body>
<h:form id="firstForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget1"/>
<h:inputText id="first_input" value="#{multiFormBean.inputText1}"/>
<h:commandButton id="click1" action="#{multiFormBean.doSubmit1}" value="submit1" type="submit"
onclick="javascript:jsf.ajax.request(this, event, {execute:'firstForm', render:'renderTarget1 secondForm'}); return false;">
</h:commandButton>
</h:form>
<h:form id="secondForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget2"/>
<h:inputText id="second_input" value="#{multiFormBean.inputText2}"/>
<h:commandButton id="click2" action="#{multiFormBean.doSubmit2}" value="submit2" type="submit"
onclick="javascript:jsf.ajax.request(this, event, {execute:'secondForm', render:'renderTarget2 firstForm'}); return false;">
</h:commandButton>
</h:form>
</h:body>
But the following xhtml would call #PostConstruct more than once:
<h:body>
<h:form id="firstForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget1"/>
<h:inputText id="first_input" value="#{multiFormBean.inputText1}"/>
<a4j:commandButton id="click1" action="#{multiFormBean.doSubmit1}" value="submit1" type="submit" execute="#form" render="renderTarget1,secondForm"/>
</h:form>
<h:form id="secondForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget2"/>
<h:inputText id="second_input" value="#{multiFormBean.inputText2}"/>
<a4j:commandButton id="click2" action="#{multiFormBean.doSubmit2}" value="submit2" type="submit" execute="#form" render="renderTarget2,firstForm"/>
</h:form>
</h:body>
Please can anyone help me use the <a4j:commandButton> instead of <h:commandButton>
Also i see that i cannot call the method doSubmit2() with a4j commandButton
I think that problem here is in bug inside JSF2 and Richfaces4. From 4 version Richfaces started using JSF embedded ajax capabilities. And There is a bug with using multiple forms on page with ajax requests. The problem there that richfaces renders special hidden input with the id of currently rendered view state. This id is changed when new view is rendered. And it is also submitted with every request to show that it belongs to some specific view. So when you have multiple forms on the same page after first ajax request the view state is getting the wrong place and it can be not submitted again second time. Sometimes behavior looks like very very wierd with no logical description.
PostConstruct is called twice because server thinks that two requests belong to different views(view state is not sumbitted) and as far as bean is view scoped it is created twice. After clicking aroung ajax can completelly stop working with this because server woukd not recognize the view(probably what you see when you can not click second submit button).
In the first place I recommend you to use latest available version of JSF and Richfaces. This bug (and many more) may be already fixed there.
Why after selecting an item in this code, the cities component does not get rendered?
<h:form prependId="false">
<h:panelGrid columns="1">
<h:selectOneMenu value="#{enumBeanStatus.selectedRegion}">
<f:selectItems id="selectItem" value="#{enumBean.regions}" var="region" itemLabel="#{region.label}"/>
<f:ajax listener="#{enumBean.loadCities}" render="cities"/>
</h:selectOneMenu>
<h:outputText id="cities" value="#{enumBean.cities}"/>
</h:panelGrid>
</h:form>
It does send a POST with the selected Region, model gets updated correctly, but the <h:outputText> Component is not rendered.
One of the backing beans:
#Named
public class EnumBean {
private List<Region> regions;
private List<City> cities;
#Inject
EnumBeanStatus enumBeanStatus; //This one is CDI #ApplicationScoped & #Named
// Code...
public void loadCities(){
setCities(City.getCitiesByRegion(enumBeanStatus.getSelectedRegion()));
}
// Getters and Setters
}
Remove prependId="false" from the <h:form>. It prevents <f:ajax> from resolving the right component based on a relative client ID.
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
UIForm with prependId="false" breaks <f:ajax render>