3 cascading dropdown menus with Ajax - ajax

I want to modify the example "ajaxify select" in PrimeFaces showcase application and introduce a third p:selectOneMenu with chooses depending on selection of second p:selectOneMenu.
Here is the modified code :
<h:form>
<p:growl id="msgs" showDetail="true"/>
<p:panel header="Double Combo" style="margin-bottom:10px;">
<h:panelGrid columns="3" cellpadding="5">
<p:selectOneMenu id="city" value="#{pprBean.city}">
<f:selectItem itemLabel="Select City" itemValue="" />
<f:selectItems value="#{pprBean.cities}" />
<p:ajax update="suburbs"
listener="#{pprBean.handleCityChange}" />
</p:selectOneMenu>
<p:selectOneMenu id="suburbs" value="#{pprBean.suburb}">
<f:selectItem itemLabel="Select Suburb" itemValue="" />
<f:selectItems value="#{pprBean.suburbs}" />
<p:ajax update="subsuburbs"
listener="#{pprBean.handleSuburbChange}" />
</p:selectOneMenu>
<p:selectOneMenu id="subsuburbs" value="#{pprBean.subsuburb}">
<f:selectItem itemLabel="Select Subsuburb" itemValue="" />
<f:selectItems value="#{pprBean.subsuburbs}" />
</p:selectOneMenu>
</h:panelGrid>
<p:separator />
<p:commandButton value="Submit" update="msgs"
actionListener="#{pprBean.displayLocation}"/>
</p:panel>
</h:form>
But the listener function #{pprBean.handleSuburbChange} is never executed. I saw in another forum that the dynamic code in ajax response don't include tag other that tag indicated in update attribute, but how can I do then?
In PPRBean code I added:
#Named("pprBean")
#RequestScoped
public class PPRBean implements Serializable {
// ...
public void handleSuburbChange() {
if (suburb != null && !suburb.equals("")) {
subsuburbs = subsuburbsData.get(suburb);
} else {
subsuburbs = new HashMap<String, String>();
}
log.info("subsuburbs:" + subsuburbs);
}
// ...

The listener won't be invoked if the selected item cannot be processed. You've put the bean in the request scope which means that it's garbaged when the response associated with the request is finished (i.e. when the browser is finished loading the page). So, when you submit the form, a new request will be fired and a brand new bean is created which in your case apparently doesn't prepare/prefill the list of suburbs in the (post)constructor in order to find the selected item (and execute the listener).
To fix this, you'd normally need to put the bean in the view scope by the JSF #ViewScoped annotation along with #ManagedBean.
#ManagedBean
#ViewScoped
public class Bean {
// ...
}
This way the bean instance will live as long as you're interacting with the same view. But as you're using CDI to manage the beans instead of JSF, you'd need to use #ConversationScoped instead and control the Conversation yourself.
#Named
#ConversationScoped
public class Bean {
#Inject
private Conversation conversation;
#PostConstruct
public void init() {
conversation.begin();
// ...
}
public void submit() {
// ...
conversation.end();
}
}

Related

primefaces dont validate ajax rendered component

<h:form id="formEdit">
<p:selectOneMenu value="#{testView.selection}"
required="true">
<f:selectItem itemValue="noMenu" itemLabel="selectOneMenu not rendered"/>
<f:selectItem itemValue="haveMenu" itemLabel="selectOneMenu rendered"/>
<p:ajax update="formEdit"/>
</p:selectOneMenu>
<p:panel>
<p:selectOneMenu id="conditionallyRnedered" value="#{testView.value}"
rendered="#{testView.selection eq 'haveMenu'}"
required="true">
<f:selectItem itemValue="#{null}" itemLabel="-" noSelectionOption="true"/>
</p:selectOneMenu>
</p:panel>
<p:messages id="messages"/>
<p:commandButton value="Submit"/>
</h:form>
Component "conditionallyRnedered" is required, and rendered on page after i select "haveMenu" value in first menu. This component have only empty option and initialy its not rendered on page. If i press Submit button, then response is:
<partial-response><changes>
<update id="javax.faces.ViewState"><![CDATA[stateless]]></update>
</changes></partial-response>
There is no validation error. If i change value of rendered attribute in "conditionallyRnedered" from "#{testView.selection eq 'haveMenu'}" to just "true", then response is:
<partial-response><changes>
<update id="javax.faces.ViewState"><![CDATA[stateless]]></update>
<extension ln="primefaces" type="args">{"validationFailed":true}</extension></changes>
</partial-response>
Validation error returned. The questions is:
Why conditionally rendered component is not validated?
It is possible to make them validated?
UPD
Originally in my question is absent Bean source code, in which Bean declared as #ViewScoped. After read #BalusC comment, i try to change scope from #ViewScoped to #SessionScoped, and after that validation is working correctly. Wherein javax.faces.ViewState in response changed from stateless to some view id:
<update id="javax.faces.ViewState">-5902669082498843838:729675320168079573</update>
I still doubt, this is solution or still workaround, because I thought that instance of #ViewScoped bean is exist while we dont left the page. Maybe this behavior is caused by the fact that in the same page present another bean, with #SessionScoped scope.
It failed for the technical reason explained in this Q&A: Form submit in conditionally rendered component is not processed. In a nutshell, JSF will re-check the rendered attribute during processing the form submit/conversion/validation and skip components which aren't rendered during that moment. The answer is to use a #ViewScoped bean.
That it still failed in spite of that you're actually using a #ViewScoped bean is because you're using a stateless view via <f:view transient="true">, as confirmed by the actual javax.faces.ViewState value and What is the usefulness of statelessness in JSF? In other words, JSF won't save/restore the view, including any view scoped beans. Those beans will technically behave like #RequestScoped beans and thus be recreated on every request, resetting their properties to defaults everytime.
To solve your problem, just turn off stateless view by removing <f:view transient="true"> and keep your bean #ViewScoped.
#bobzer,
primefaces commandButton has become ajax="true" by default. So when i set ajax="false", the form is submitted and i can see validation errors
i get
My xhtml:
<h:form id="formEdit">
<p:selectOneMenu value="#{testView.selection}" required="true">
<f:selectItem itemValue="noMenu"
itemLabel="selectOneMenu not rendered" />
<f:selectItem itemValue="haveMenu" itemLabel="selectOneMenu rendered" />
<p:ajax update="formEdit" />
</p:selectOneMenu>
<p:panel>
<p:selectOneMenu id="conditionallyRnedered" value="#{testView.value}"
rendered="#{testView.selection eq 'haveMenu'}" required="true">
<f:selectItem itemValue="#{null}" itemLabel="-"
noSelectionOption="true" />
</p:selectOneMenu>
</p:panel>
<p:messages id="messages" />
<p:commandButton value="Submit" ajax="false"/>
</h:form>
My Bean
package citi.manageID.framework.admin.roleMgmt;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named
#ViewScoped
public class TestView {
private String selection="";
private String value="";
public String getSelection() {
return selection;
}
public void setSelection(String selection) {
this.selection = selection;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

p:selectOneMenu ajax does not fire within p:dataGrid

I have a selectOneMenu rendered for each row of my dataGrid. The problem is the method of the ajax listener is not called when the selection changes.
If I use the same selectOneMenu outside the dataGrid, it works fine. Same behaviour occurs with p:selectBooleanCheckbox.
XHTML page:
<h:form id="form2">
<p:dataGrid id="gridC" widgetVar="gridC"
value="#{myBean.comp}" var="site" columns="1" rowIndexVar="siteIndex">
<p:column>
<h:outputText value="#{site.sito}" />
</p:column>
<p:column>
<p:selectOneMenu id="stato" value="#{site.stateId}"
required="true">
<p:ajax update="#form :tabView:frm_buttons" global="false"
listener="#{myBean.testChangeState}" />
<f:selectItems value="#{myBean.siteStates}" var="s"
itemLabel="#{s.state}" itemValue="#{s.stateId}" />
</p:selectOneMenu>
</p:column>
</p:dataGrid>
</h:form>
Managed bean:
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
private SiteState siteStates;
private Comp comp;
// getters and setters...
public void testChangeState() {
System.out.println("Test change state fired.");
}
}
SiteState bean:
public class SiteState implements Serializable {
private String state;
private String stateId;
// getters and setters...
}
Found the secret.
The data grid is within a tab of an accordion panel, and I used an id like this:
<p:tab id="sito#{sito.idSitoStoccaggio}"
This is not the case, because it produces strange behaviours in some situations, like events not firing from within a data grid, for example.
Switching to:
<p:tab id="sito"
resolved my issue.

JavaServer Faces ajax control not updating (enabling / disabling)

here is a snippet from my JSF page:
<p:selectBooleanCheckbox value="#{FormXYZ_01.propertyNone0}">
<p:ajax event="blur" render="propertyNone0" />
</p:selectBooleanCheckbox>
<p:inputTextarea id="propertyNone0" disabled="#{FormXYZ.propertyNone0}" rows="3" styleClass="fixed400" />
Here is the relevant code from my backing bean:
#ManagedBean(name="FormXYZ_01")
#SessionScoped
public class FormXYZ_01 implements Serializable {
private Boolean propertyNone0;
public Boolean getPropertyNone0() {return propertyNone0;}
public void setPropertyNone0(Boolean propertyNone0) {this.propertyNone0 = propertyNone0;}
My ultimate goal is for the textbox to disable when the selectBooleanCheckbox is checked. I am very new to JSF and am using primefaces.
Thanks!
Here is the code that ended up working:
<h:form>
<p:selectBooleanCheckbox value="#{FormXYZ_01.propertyNone0}">
<p:ajax event="change" update="ctrlPropertyDescLoc0" />
</p:selectBooleanCheckbox>
<p:inputTextarea id="ctrlPropertyDescLoc0" disabled="#{FormXYZ_01.propertyNone0}" cols="27" rows="3" />
</h:form>
The take-aways are, event had to be "change" and update had to point id attribute of the target control.
Also, don't forget to wrap your controls in form tags!
<h:form>...</h:form>

JSF 2: access selected value of selectOneMenu in a form BEFORE submit

VIEW
<h:form id="main_form">
<p:inputText id="title" required="true" label="Title" value="#{myBean.myLink.title}" immediate="true" />
<p:selectOneMenu id="scope" required="true" label="Scope" value="#{myBean.myLink.scope}" immediate="true" >
<f:selectItem itemLabel="Please choose" itemValue="" />
<f:selectItems value="#{myBean.availableScopes}" id="selScope"/>
</p:selectOneMenu>
<p:inputText id="link" required="true" label="URL" value="#{myBean.myLink.link}" immediate="true">
<p:ajax event="blur" update="msgLink" listener="#{myBean.checkUrl}" />
</p:inputText>
... msgLink and other (required) elements
... submit button
</h:form>
Managed Bean
#Component("myBean")
#Scope("session")
public class MyBean implements Serializable {
private Link myLink;
private Map<String, String> availableScopes;
public MyBean() {
this.availableScopes = new HashMap<String, String>();
this.availableScopes.put("Intranet", "Intranet");
this.availableScopes.put("Internet", "Internet");
}
// setter/getters etc.
public void checkUrl() {
System.out.println(myLink.getTitle()); // works
System.out.println(myLink.getScope()); // DOES NOT work
System.out.println(myLink.getLink()); // works
}
}
I want to check the URL depending of the selected scope before submitting the form. But the called method can access the inputText values of the object. Not the value chosen in selectOneMenu.
I have tried it with getExternalContext().getSessionMap().get("scope") but the SessionMap is null at that time.
Any chance to access the selected value of the combo box?
Thanks
Jim
The <p:ajax> (and <f:ajax>) inside an UIInput component executes/processes by default the current UIInput component (#this) only, not others.
If you want to execute/process all those UIInput components when the listener method is to be invoked, then you should specify that as such in <p:ajax process> (or <f:ajax execute>) attribute:
<p:inputText id="title" ... />
<p:selectOneMenu id="scope" ... >
...
</p:selectOneMenu>
<p:inputText id="link" ...>
<p:ajax process="title scope link" ... />
</p:inputText>
Unrelated to the concrete problem, I wonder how all those immediate="true" attributes are useful in this context. Are you certain you need them?

How to save 2 dependent selectOneMenu values

I'm running in a little issue here regarding jsf related dropdown selection.
I have 2 dropdown selection: the first one is independent, the second one shows result depending from This is the code:
<h:panelGroup id="addressPanel">
<h:outputLabel styleClass="label" value="Provincia: " />
<h:selectOneMenu onchange="updateCombos()"
value="#{indirizzoCtrl.codiceProvincia}" >
<f:selectItem itemValue="" itemLabel=""></f:selectItem>
<f:selectItems value="#{indirizzoCtrl.allProvincia}" var="c"
itemLabel="#{c.nome}" itemValue="#{c.siglaProvincia}" />
</h:selectOneMenu>
<h:outputLabel styleClass="label" value="Comune: " />
<h:selectOneMenu
value="#{indirizzoCtrl.codiceComune}" >
<f:selectItem itemValue="" itemLabel=""></f:selectItem>
<f:selectItems value="#{indirizzoCtrl.allComuni}" var="c"
itemLabel="#{c.descrizione}" itemValue="#{c.codiceComune}" />
</h:selectOneMenu>
</h:panelGrid>
</h:panelGroup>
<p:remoteCommand name="updateCombos" update="addressPanel masterForm:msg" />
<p:commandButton styleClass="commandButton" value="Save"
actionListener="#{indirizzoCtrl.save}">
</p:commandButton>
Well, when the user save the form after selecting both the value, the managed bean indirizzoCtrl (request scoped) cannot map the value of the second dropdown back to the list, because there's no list.
In fact the #{indirizzoCtrl.allComuni} call a getter that retrieve the data from the DB only if indirizzoCtrl.codiceProvincia!=null... and that's false before the update model phase.
So the first time the getter for the list is called cannot retrieve any values, and that's bring the update model phase to fail.
How can I handle this scenario... I think it's a pretty common one, so I'm missing something here...
Put the bean in the view scope instead. It will live as long as you're interacting with the same view by ajax. A request scoped bean get indeed recreated on every single request, also ajax requests, so bean properties would reinitialize to their defaults.
#ManagedBean
#ViewScoped
public class IndidizzoCtrl implements Serializable {
// ...
}
See also:
How to load and display dependent h:selectOneMenu on change of a h:selectOneMenu
How to choose the right bean scope?
Unrelated to the concrete problem, I also strongly recommend to change your getter methods to not do any business job, but just return data. Do the business job in (action)listener methods instead. E.g.
<h:selectOneMenu value="#{bean.menu1item}">
<f:selectItems value="#{bean.menu1items}" />
<f:ajax listener="#{bean.updateMenu2}" render="menu2" />
</h:selectOneMenu>
<h:selectOneMenu id="menu2" value="#{bean.menu2item}">
<f:selectItems value="#{bean.menu2items}" />
</h:selectOneMenu>
with
public void updateMenu2() {
menu2items = loadItBasedOn(menu1item);
}
See also:
Why JSF calls getters multiple times

Resources