strange jsf panelgroup binding -> h:selectOneMenu validation Exception - validation

lets start simple:
- an easy search form
- two h:selectOneMenu components are declared inside a form
- the second selectOneMenu, is refreshed base on selecting an item of the first selectOneMenu (with ajax)
For this, i use a central Bean in request scope, because the two selectOneMenus are declared on many other pages, so i dont need to define the two following methods multiple times:
pageSupport:
#SuppressWarnings("unchecked")
public List<BranchenRubrik> getLst_branchenRubrik() {
if(lst_branchenRubrik == null) {
Session session = hibernate.InitSessionFactory.getInstance().getCurrentSession();
Transaction tx = session.beginTransaction();
this.lst_branchenRubrik = session.createQuery("from BranchenRubrik").list();
tx.commit();
}
return lst_branchenRubrik;
}
// Loading Subkats with parameter
#SuppressWarnings("unchecked")
public List<BranchenRubrikSub> getBranchenRubrikSub(long p_parent) {
List<BranchenRubrikSub> lst_branchenRubrikSub = new ArrayList<BranchenRubrikSub>();
if(p_parent > 0) {
Session session = hibernate.InitSessionFactory.getInstance().getCurrentSession();
Transaction tx = session.beginTransaction();
lst_branchenRubrikSub = session.createQuery("from BranchenRubrikSub BRS WHERE BRS.parentRubrik.id = :p1").setLong("p1",p_parent).list();
tx.commit();
}
return lst_branchenRubrikSub;
}
VDL:
<p:selectOneMenu value="#{searchBean2.fvz.branchenRubrikID}">
<f:selectItem itemLabel="Bitte wählen" itemValue="0"/>
<f:selectItems value="#{pageSupport.lst_branchenRubrik}" var="rubrik" itemValue="#{rubrik.id}" itemLabel="#{rubrik.rubrik}"/>
<f:ajax render="uiBranchenSubKat"/>
</p:selectOneMenu>
<h:outputText value="Unterkategorie" />
<p:selectOneMenu id="uiBranchenSubKat" value="#{searchBean2.fvz.branchenRubrikSubID}">
<f:selectItems value="#{pageSupport.getBranchenRubrikSub(searchBean2.fvz.branchenRubrikID)}" var="brs" itemLabel="#{brs.rubrik}" itemValue="#{brs.id}"/>
</p:selectOneMenu>
this works fine, i can submit the form and all data are saved and will be re-displayed.
Now, i want to include an h:panelGroup with binding to a methode, which build a pagination menue.
If i include the h:panelGroup binding="#{searchBean2.paginationMenu}"/> then, i cant submit the form, because it says that the value for the second h:selectOneMenu is not valid.
if i remove the "h:panelGroup binding" all working as expected.
The h:panelgroup can also binded to an empty methode "return new HtmlPanelGroup()"
then, the error occurs again.
looks like, that the component binding, breaks some validation.
thanks for your time

Related

How can I check if multiple checkboxes are checked with JSF / AjaxBehaviorEvent

I have multiple checkboxes - they are given the same id, "choosen" in the xhtml view code.
I have added an Ajax event listener for them, like so:
<ui:repeat var="posts"
value="#{postBacking.postsOverview.posts}">
<h:selectBooleanCheckbox id="choosen"
styleClass="check-margin"
value="#{posts.choosen}" rendered="#{posts.declined =='No'}">
<f:ajax listener="#{postsBacking.isPostsChosen}" event="click" render="#form" execute="#form"/>
</h:selectBooleanCheckbox>
</ui:repeat>
In the listener method in my backingBean, I would like to check if any of these checkboxes are checked, and then set a button disabled if no checkboxes are marked - and enabled if one or more is set.
But how do I get hold of the values of all checkboxes - can I use the AjaxBehaviorEvent objet for that or is there some other way?
While processing the ajax event listener, the checkbox values should normally have been applied to your data model where you can look up the state of user choice. Depending on that state, simply toggle a boolean bean property which disables the command button:
#Named
#ViewScoped
public class MyBean implements Serializable {
private List<Post> posts;
private boolean buttonDisabled = true;
public void ajaxEventListener(BehaviorEvent e) {
boolean anythingChosen = false;
for (Post post : posts) {
if (post.isChosen() && "No".equals(post.getDeclined())) {
anythingChosen = true;
break;
}
}
// or alternatively using the stream api:
// anythingChosen = posts.stream().filter(Post::isChosen).map(Post::getDeclined)
// .anyMatch("No"::equals);
setButtonDisabled(!anythingChosen);
}
// getters, setters ...
}
Using the following form, the command button is disabled as long as no checkbox is checked:
<h:form>
<ui:repeat var="post" value="#{myBean.posts}">
<h:selectBooleanCheckbox value="#{post.chosen}">
<f:ajax event="click" listener="#{myBean.ajaxEventListener}" render="#form" execute="#form"/>
</h:selectBooleanCheckbox>
</ui:repeat>
<h:commandButton action="#{myBean.doSomething()}" value="doSomething"
disabled="#{myBean.buttonDisabled}" />
</h:form>
You can use valueChangeListener rather than using listener and event attributes. The valueChangeListener will be triggered every time you check/uncheck the checkbox.
To get hold of the values when thevalueChangeListener is invoked, you can loop through the postBacking.postsOverview.posts to see if any value is checked.
Don't forget to update the button on <f:ajax render="#form btnId"/> to enable/ disable it.

Creating Dropdown Box using AJAX with JSF/Primefaces

I am trying to create a simple dropdown box using Ajax and JSF 2.0/primeface. Based on First Dropdown selection second dropdown box is populated using AJAX call.
When I select first drop down it correctly populated the second dropdown box based on the Ajax call. But When I make selection in the second dropdown and click the button {which basically submit the form for some action}, It give error message
"formViewBusinessCode:selectedBusinessCode: Validation Error: Value is not valid"
When I check in console that is says the value for "selectedBusinessCode"{Id of second dropdown} is null. I am puzzled becuase it populates correctly but only after selection it gives error that value is not valid (basically null), Why the selected value is not reaching to the bean? Can someone please point what I am missing here, TIA
xhtml code is as below
<h:outputText styleClass="outputText" value="#{constant.businessCodeGroup}"></h:outputText>
<h:selectOneMenu id="selectedBusinessCodeGroup" value="#{viewBusinessCodeBean.selectedBusinessCodeGroup}" >
<f:selectItem itemValue="SELCT" itemLabel="Select Business Code Group" />
<f:selectItems value="#{viewBusinessCodeBean.businessCodeGroupList}" />
<p:ajax listener="#{viewBusinessCodeBean.getOnlyBusinessCodeListByAjaxCall}" event="change" update="selectedBusinessCode" process="#this"/>
</h:selectOneMenu>
<h:outputText styleClass="outputText" value="#{constant.businessCode}"></h:outputText>
<h:selectOneMenu id="selectedBusinessCode" value="#{viewBusinessCodeBean.selectedBusinessCode}">
<f:selectItem itemValue="SELCT" itemLabel="Select Business Code" />
<f:selectItems value="#{viewBusinessCodeBean.businessCodeList}" itemLable="#{viewBusinessCodeBean.businessCodeList.getlable}"
itemValue="#{viewBusinessCodeBean.businessCodeList.getValue}" />
</h:selectOneMenu>
<h:commandButton value="View" action="#{viewBusinessCodeBean.getOnlyBusinessCodeDescription}"></h:commandButton>
The bean coding is as below. it is a #ManagedBean
To Populate First Dropdown box
public ViewBusinessCodeBean() {
logger.entering(CLASS_NAME);
this.businessCodeGroupList = new ArrayList<SelectItem>();
List<String>tempBusinessCodeList = new BusinessCodeTableServices().getBusinessCodeGroupList();
Iterator<String>iterator = tempBusinessCodeList.iterator();
while(iterator.hasNext()){
String businessCodeGroup = iterator.next();
logger.debug(businessCodeGroup);
SelectItem item = new SelectItem(businessCodeGroup);
businessCodeGroupList.add(item);
}
logger.exiting(CLASS_NAME);
}
Ajax Call Method which populated second dropdown
public void getOnlyBusinessCodeListByAjaxCall() {
this.businessCodeList = new ArrayList<SelectItem>();
List<String>tempBusinessCodeList = new BusinessCodeTableServices().getOnlyBusinessCodeList(getSelectedBusinessCodeGroup());
Iterator<String>iterator = tempBusinessCodeList.iterator();
while(iterator.hasNext()){
String businessCode = iterator.next();
SelectItem item = new SelectItem(businessCode,businessCode,businessCode);
businessCodeList.add(item);
}
}
Your bean is apparently in the request scope. A request scoped bean is reconstructed on every request with all properties set to default. Your validation error is caused because businessCodeList property has become null/empty during the request of processing the form submit.
Putting the bean in the view scope should fix this problem.
See also:
Validation Error: Value is not valid
How to choose the right bean scope?

When to use valueChangeListener or f:ajax listener?

What's the difference between the following two pieces of code - with regards to listener placement?
<h:selectOneMenu ...>
<f:selectItems ... />
<f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>
and
<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
<f:selectItems ... />
</h:selectOneMenu>
The valueChangeListener will only be invoked when the form is submitted and the submitted value is different from the initial value. It's thus not invoked when only the HTML DOM change event is fired. If you would like to submit the form during the HTML DOM change event, then you'd need to add another <f:ajax/> without a listener(!) to the input component. It will cause a form submit which processes only the current component (as in execute="#this").
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
When using <f:ajax listener> instead of valueChangeListener, it would by default executed during the HTML DOM change event already. Inside UICommand components and input components representing a checkbox or radiobutton, it would be by default executed during the HTML DOM click event only.
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Another major difference is that the valueChangeListener method is invoked during the end of the PROCESS_VALIDATIONS phase. At that moment, the submitted value is not been updated in the model yet. So you cannot get it by just accessing the bean property which is bound to the input component's value. You need to get it by ValueChangeEvent#getNewValue(). The old value is by the way also available by ValueChangeEvent#getOldValue().
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
// ...
}
The <f:ajax listener> method is invoked during INVOKE_APPLICATION phase. At that moment, the submitted value is already been updated in the model. You can just get it by directly accessing the bean property which is bound to the input component's value.
private Object value; // +getter+setter.
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value); // Look, (new) value is already set.
}
Also, if you would need to update another property based on the submitted value, then it would fail when you're using valueChangeListener as the updated property can be overridden by the submitted value during the subsequent UPDATE_MODEL_VALUES phase. That's exactly why you see in old JSF 1.x applications/tutorials/resources that a valueChangeListener is in such construct been used in combination with immediate="true" and FacesContext#renderResponse() to prevent that from happening. After all, using the valueChangeListener to execute business actions has actually always been a hack/workaround.
Summarized: Use the valueChangeListener only if you need to intercept on the actual value change itself. I.e. you're actually interested in both the old and the new value (e.g. to log them).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Use the <f:ajax listener> only if you need to execute a business action on the newly changed value. I.e. you're actually interested in only the new value (e.g. to populate a second dropdown).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
If you're actually also interested in the old value while executing a business action, then fall back to valueChangeListener, but queue it to the INVOKE_APPLICATION phase.
public void changeListener(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println(newValue.equals(value)); // true
// ...
}
for the first fragment (ajax listener attribute):
The "listener" attribute of an ajax tag is a method that is called on the server side every time the ajax function happens on the client side. For instance, you could use this attribute to specify a server side function to call every time the user pressed a key
but the second fragment (valueChangeListener) :
The ValueChangeListener will only be called when the form is submitted, not when the value of the input is changed
*you might like to view this handy answer

<f:validator disabled flag not working

I've created a custom validator for my project, it simply checks the select ones value and 'validates' the value is not '0'. We have a standard (I'm sure not uncommon) of manually setting the first value of our selectOneMenu compents to:
<f:selectItem itemValue="0"
itemLabel="-- Select One --"/>
Which works fine, but then makes the component always pass the required check. So this validator simply treats this value as if there was no selection made.
SelectOneMenu example:
<h:selectOneMenu id="eligibility"
value="#{reg.eligibility}"
required="#{reg.fieldsRequired}">
<f:selectItem itemValue="0"
itemLabel="-- Select One --"/>
<f:selectItems value="#{reg.eligibilityList}" />
<f:validator validatorId="selectOneValidator"
disabled="#{!reg.fieldsRequired}"/>
Custom Validator:
#FacesValidator("selectOneValidator")
public class SelectOneValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent uiComponent, Object o) throws ValidatorException {
String val = null;
if (uiComponent instanceof HtmlSelectOneMenu) {
HtmlSelectOneMenu oneMenu = (HtmlSelectOneMenu) uiComponent;
if (oneMenu.isRequired() && !oneMenu.isDisabled()) {
if (o instanceof String) {
val = (String) o;
} else if (o instanceof Number) {
val = String.valueOf(o);
}
if ("0".equals(val)) {
FacesMessage msg = new FacesMessage();
msg.setSummary("Please select a value from the list.");
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(msg);
}
}
}
}
}
This has worked just fine thus far, however, the current use-case I'm running into trouble.
My page has multiple SelectOneMenus one of which toggles the required and disabled attributes via an ajax call for the page. I'm not having any issues with the required="#{reg.fieldsRequired}", however; the disabled="#{!reg.fieldsRequired}" attribute on my custom validator does not seem to make a difference. I'm just thinking out loud, but when the page first loads the #{reg.fieldsRequired} expression is false. If I then change the SelectOneMenu to set this boolean value to true, then press the submit button, the disabled attribute doesn't seem to have been set. I wondered if this is simply a ajax issue and that all of components simply needed to be re-renderd so I added the #form in my ajax call: <a4j:ajax render="#form" listener="#{reg.saveActionChanged}"/> in hopes that would fix the problem, but no difference in the behavior.
Environment:
JSF 2.0.3
Tomcat 6.0.14
ajax call being made with RichFaces 4.0
Any help is most appreciated!
Sorry, I can't reproduce your problem with JSF 2.1.3. The <f:validator disabled> works as expected.
However, as a completely different alternative, you can in this particular case just make use of the standard required validator. You only need to set the item value to #{null} instead of 0.
<f:selectItem itemValue="#{null}" itemLabel="-- Select One --"/>
This way you don't need the custom validator. The message can be set as requiredMessage attribute of the input component.
<h:selectOneMenu requiredMessage="Please select a value from the list.">

Value remains in form field after it is cleared in bean in JSF2

In my JSF2 application, I have "Clear" button, which is supposed to clear all the fields. However, it doesn't always work.
My page fragment:
<h:form id="bi">
<h:inputText value="#{bean.entity.firstname}" />
<h:inputText value="#{bean.entity.surname}" />
<h:commandButton value="Clear" immediate="true" action="#{bean.clear}">
<f:ajax render="bi" />
</h:commandButton>
<h:commandButton value="Submit" action="#{bean.submit}" />
</h:form>
And clear() method in my bean:
public void clear() {
entity = new Entity();
}
If I enter values in the fields, and click "Clear", everything is cleared as expected. However, consider such scenario:
1. Enter value only in one field (both are required by JSR303 annotations on entity).
2. Click "Submit". Error message appears.
3. Click "Clear".
Entered value remains. Why is it not cleared?
Moreover, if I clear it by hand, and click "Clear", it returns to the field. I checked that it comes to the browser in partial response after clicking "Clear" button. I suspect it has something to do with view state.
Moreover, if I add validator="#{bean.validate}" to the field, it enter this validation. Even if button has immediate="true" attribute. Why? Shouldn't immediate button ommit validation?
You've run into a more or less well-known issue regarding updating components for which validation has already happened.
This post is rather old, but still relevant: http://ishabalov.blogspot.com/2007/08/sad-story-about-uiinput.html
There is a community created solution for A4J in JSF 1.2 posted here: http://community.jboss.org/thread/8446?start=15&tstart=0
But unfortunately, this doesn't work directly in JSF 2.0 and in your case it wouldn't work at all since it's A4J specific. Nevertheless it might be a source of inspiration.
Basically you need to walk the component tree and clear its state. The neatest thing is to clear exactly the state of the components that you are going to re-render. But you might take the brute-force approach and just clear all if your particular application or page can tolerate that.
I wound up having to avoid submit or action to get the form to clear properly. I used actionListener with a void bean method instead.
But then I faced the problem of conditionally needing navigation which is usually done with a String method from action. I used ExternalContext.redirect() to accomplish that which I learned from the following:
JSF PostConstruct Exception Handling - Redirect
JSF navigation redirect to previous page
my page code:
<p:commandButton value="Login" update=":loginForm"
actionListener="#{loginBean.login}"/>
my bean code:
public void login() {
RtsLDAPAD laLdap = new RtsLDAPAD();
boolean lbAuthenticated = false;
try
{
lbAuthenticated = laLdap.login(userName, password);
System.out.println(
"The Result is " + lbAuthenticated + " for " + userName);
}
catch (Exception aeRTSEx)
{
aeRTSEx.printStackTrace();
}
if (lbAuthenticated) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("taskform.jsf");
} catch (IOException e) {
e.printStackTrace();
}
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null,
new FacesMessage("Login failed for " + userName + "."));
UIViewRoot uiViewRoot = facesContext.getViewRoot();
HtmlInputText inputText = null;
Password pwd = null;
inputText = (HtmlInputText) uiViewRoot.findComponent("loginForm:username");
inputText.setSubmittedValue(null);
inputText.setValue(null);
inputText.setLocalValueSet(false);
inputText.setValid(true);
pwd = (Password) uiViewRoot.findComponent("loginForm:password");
pwd.setSubmittedValue(null);
pwd.setValue(null);
pwd.setLocalValueSet(false);
pwd.setValid(true);
userName = null;
password = null;
}
}

Resources