Richfaces Datatable loses submitted value of inputs on validation fail - validation

I have two inputs - one inside a "normal" h:dataTable and one inside a rich:dataTable When I submit a wrong value, i.e. validation fails, the "normal" one keeps the value I submitted while the second one loses it. See the following code snippets (enter any value an press the button):
ManagedBean
#ManagedBean
#ViewScoped
public class TestController implements Serializable {
private static final long serialVersionUID = -484022507596298941L;
private String[] stringArray1 = {"Element 1", "Element 2"}; // + Getter
private String[] stringArray2 = {"Element A", "Element B"}; // + Getter
private Map<String, String> inputValues = new HashMap<String, String>(4); // + Getter
public TestController() {
inputValues.put(stringArray1[0], "");
inputValues.put(stringArray1[1], "");
inputValues.put(stringArray2[0], "");
inputValues.put(stringArray2[1], "");
}
public void doSomething() {
System.out.println("Did something");
}
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) {
throw new ValidatorException(new FacesMessage("This can never be valid."));
}
}
View
<h:form>
<h1>h:dataTable</h1>
<h:dataTable id="table1" value="#{testController.stringArray1}" var="string" columnClasses="inactive">
<h:column>
<h:outputText value="#{string}:"/>
<h:inputText id="someInput" value="#{testController.inputValues[string]}" validator="#{testController.validate}"/>
<h:message for="someInput" id="msg" style="color: red;"/>
</h:column>
</h:dataTable>
<h1>rich:dataTable</h1>
<rich:dataTable id="table2" value="#{testController.stringArray2}" var="string">
<rich:column>
<h:outputText value="#{string}:"/>
<h:inputText id="someInput" value="#{testController.inputValues[string]}" validator="#{testController.validate}"/>
<h:message for="someInput" id="msg" style="color: red;"/>
</rich:column>
</rich:dataTable>
<h:commandButton id="button" action="#{testController.doSomething}" value="do something"/>
</h:form>
Is this known Richfaces behaviour or a bug of some kind? Is there a way to make it behave the same way the normal JSF-DataTable does? Using h:dataTable instead is not always an option and losing your "I-was-just-about-to-correct-it" input is rather annoying.
ADDITION:
I just checked the behaviour of ui:repeat and a4j:repeat and it's just the same: ui:repeat keeps the submitted value while a4j:repeat does not.
UPDATE: Re-worked example code to rule out some possible problems as mentioned in comments (input fields now point to different values; only one form element).
Tested on Mojarra 2.1.21 with RichFaces 4.3.7 and JBoss AS 7 plus on Mojarra 2.2.7 with RichFaces 4.5.0 Alpha3 and JBoss Wildlfy - same result.

I just tried each form of your page separately with Richefaces 4.3.7 and Mojarra 2.2.6 and it's perfectly working! i didn't noticed any abnormal behavior, when validation fails i didn't lost any values. That means that there is no Validation issues with the Richfaces components.
However, When using the two forms in a single page, i can notice that when i submit the first form the inputText of the second form loses it's value, while if we submit the form2 the inputText of the first form don't lost it's value, in my guess its because JSF stored the state of it's HTML components in the javax.faces.ViewState and doesn't do the same for Richfaces components, using Firebug you can easily verify that the only common request parameter between those two POST requests is the javax.faces.ViewState.

Related

Trying to call ajax listener method via onevent="#{checkIfUsernameAvailable}"

I have a jsf page and an input field. When the event of this input field being blurred, I would like the method checkIfUsernameAvailable() of my ManagedBean to be called. Then the image should be rendered. The problem is that that method is either never called or just not found, no matter what I do. So could someone tell me how I should do it ?
My code here doesn't work, obviously because I never call the method checkIfUsernameAvailable in my jsf. I'm sure the answer is simple but I tried so much and I just don't find it. So I removed my tried calls to this method in the code so it's without errors.
on the f: ajax i put
JSF:
<h:inputText id="username" required="true" value="#{subscribeUser.user.username}">
<f:ajax event="blur" render="usernameCheck"}"></f:ajax>
</h:inputText>
<h:panelGroup id="usernameCheck" >
<h:graphicImage value="resources/images/success_indicator.png" rendered="#{subscribeUser.isIndicatorVisible.usernameSuccess}">
</h:graphicImage>
<h:outputText id="usernameError" value="#{subscribeUser.isIndicatorVisible.usernameSuccess}"/>
</h:panelGroup>
So you see subscribeUser.isIndicatorVisible.usernameSuccess should always be false. I would like that when the input field is blurred that I'd call checkIfUserAvailable() so then it would be true and my image would then be rendered.
ManagedBean:
public class SubscribeUser {
private User user;
private Map<String, Boolean> isIndicatorVisible;
#EJB
Userpersistence up;
public SubscribeUser() {
this.user = new User();
this.isIndicatorVisible = new HashMap<>();
this.isIndicatorVisible.put("usernameSuccess", false);
//...
}
public void checkIfUsernameAvailable() {
this.isIndicatorVisible.replace("usernameSuccess", true);
}
//getters & setters
}
You need the listener attribute.
<f:ajax event="blur" listener="#{subscribeUser.checkIfUsernameAvailable()}" render="usernameCheck"}" />
See also:
Java EE 7 tutorial - Sending an ajax request
By the way, validation is usually done by a normal validator, not an action method. But I gather that you still need to learn about that part.
See also:
JSF 2.0 validation in actionListener or action method

h:form inside ui:repeat doesn't work as expected

For a huge project, I need to build multiple forms on a web page. Can't go into details, but assume to have the requested structure of a list of forms; using mojarra jsf 2.2.5
given Managed Bean:
#ManagedBean
#SessionScoped
public class Debug {
private final List<DebugBean> list;
public Debug() {
super();
this.list = new ArrayList<DebugBean>();
this.list.add(new DebugBean("label 1", "value 1"));
this.list.add(new DebugBean("label 2", "value 2"));
}
public String submit() {
LOGGER.info("list = " + this.list.toString());
return "";
}
public List<DebugBean> getList() {
return this.list;
}
}
The bean DebugBean is simple, just contains two variables label and value, both String, and its setter and getter.
Now the xhtml page:
<h:body style="height: 100%">
<ui:repeat value="#{debug.list}" var="x">
<h:form>
<h:panelGrid columns="2">
<h:outputText value="#{x.label}" />
<h:inputTextarea value="#{x.value}" />
</h:panelGrid>
<h:commandButton action="#{debug.submit}" value="ok" />
</h:form>
</ui:repeat>
</h:body>
The problem is in changing the first value. When I change the second one, the logger gives me the new value as expected. But changing the first one, the logger gives me the old list, as if I would have reloaded the complete form without any changes. What's the problem here, and more important: what can I do to make it work?
The solution is simple, but worse. I don't know why, but ui:repeat does not behave as h:dataTable does. So replacing ui:repeat by h:dataTable solves the problem, but means page layout rework (which is a bigger problem, but can be done by me).

get model value on f:ajax or a4j:ajax listener method

This is my first post on SO.
I am using JSF2 with Richfaces4 and I have the following problem:
Depending the value of a drop down menu I want some input fields in a panel to be disabled and not required otherwise those fields should be enabled and required.
I have the following in my xhtml
<h:selectOneMenu value="#{backingBean.field}" id="ResponseType">
<f:selectItems value="#{backingBean.responseTypes}" />
<f:ajax event="change" execute="#this" render="myPanel" listener="#{backingBean.responseTypeValueChange}" immediate="true"></f:ajax>
</h:selectOneMenu>
<rich:panel id="myPanel">
<h:inputText id="input1" label="label1" value="#{backingBean.input1}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
<h:inputText id="input2" label="label2" value="#{backingBean.input2}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
<h:inputText id="input3" label="label3" value="#{backingBean.input3}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
<h:inputText id="input4" label="label4" value="#{backingBean.input4}" required="#{not backingBean.flagDisabled}" disabled="#{backingBean.flagDisabled}" />
</rich:panel>
My backing bean is a Spring bean and the code is:
public class BackingBean {
private boolean flagDisabled;
private String field;
// getters and setters
public List<SelectItem> getResponseTypes() {
...
// returns values [1: Positive], [2: Negative]
}
public void responseTypeValueChange(AjaxBehaviorEvent event) {
flagDisabled = "2".equals(field);
}
}
My problem is that when the responseTypeValueChange method is invoked the field variable holds the value from the previous request. So I always get the exact opposite behavior.
I have also tried with a4j:ajax but I get the same results.
Then i changed the method to get the submittedValue from the event argument like this:
public void responseTypeValueChange(AjaxBehaviorEvent event) {
if (event.getSource() instanceof HtmlSelectOneMenu) {
HtmlSelectOneMenu source = (HtmlSelectOneMenu) event.getSource();
flagDisabled = "2".equals(source.getSubmittedValue());
}
}
The above works but how I can update the flagDisabled value and THEN invoke the method?
I feel that my solution is not the best. It is actually a hack.
Thank you.
After so much time and while investigating another matter concerning the JSF validation I figured out how to properly invoke the method without using something like:
if (event.getSource() instanceof HtmlSelectOneMenu) {
HtmlSelectOneMenu source = (HtmlSelectOneMenu) event.getSource();
flagDisabled = "2".equals(source.getSubmittedValue());
}
In the <h:selectOneMenu> I added the attribute execute="#this" in order to include only this element in the ajax request.
Strange thing is that I had it in my example here but not in the actual code.
Sorry for the misleading post guys.
BTW: This has nothing to do with the scope of the managed bean. The bean is session scoped but I created even a custom View scope for Spring and even used the JSF #ViewScope without any results.

JSF 2.0; Validator tag "disabled" depends on value from page

In my jsf application i want to validate a field which should only be validated, when one option in a SelectOneRadio is checked.
I found out, that <f:validator> has an attribute, called "disabled".
Can i use this, to check the value from another field?
I tried, but i haven't access to the value from my bean.
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}">
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
<f:validator validatorId="myValidator" disabled="#{myBean.checkedSelectOneRadioValue == 'TEST'}" />
Is there any way to reach that without writing own validatorhandler?
Thanks!
The <f:validator> is a tag handler, not an UI component. All its attributes are per definition evaluated during view build time, not during view render time. The view build time is that moment when the XHTML file is been parsed into a JSF component tree as available by context.getViewRoot(). The very same view is usually reused across postbacks to the same view by returning null/void in (ajax) actions.
So you can't let a tag handler attribute depend on a render time attribute which can change during a postback request. One of the ways is to perform that check inside the custom validator itself.
E.g.
<h:inputText>
<f:validator validatorId="myValidator" />
<f:attribute name="radio" value="#{myBean.checkedSelectOneRadioValue}" />
</h:inputText>
with
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (!"TEST".equals(component.getAttributes().get("radio"))) {
return;
}
// Perform actual validation here.
}
You can alternatively also use OmniFaces <o:validator> instead. It extends the standard <f:validator> with request based evaluation of EL in attributes.
<h:inputText>
<o:validator validatorId="myValidator" disabled="#{bean.checkedSelectOneRadioValue == 'TEST'}" />
</h:inputText>
See also the showcase example and the source code from which an extract of relevance is posted below:
#Override
public void apply(FaceletContext context, UIComponent parent) throws IOException {
if (!ComponentHandler.isNew(parent)) {
return;
}
final javax.faces.validator.Validator validator = createValidator(context);
final RenderTimeAttributes attributes = collectRenderTimeAttributes(context, validator);
final ValueExpression disabled = getValueExpression(context, "disabled", Boolean.class);
((EditableValueHolder) parent).addValidator(new javax.faces.validator.Validator() {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
if (disabled == null || Boolean.FALSE.equals(disabled.getValue(context.getELContext()))) {
attributes.invokeSetters(context.getELContext(), validator);
validator.validate(context, component, value);
}
}
});
}
With JSF 2.0 you can use f:ajax for a partial submit. Add this tag to your h:selectOneRadio:
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}">
<f:ajax render="idOfInputText"/>
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
...
<h:inputText id="idOfInputText">
<f:validator validatorId="myValidator"
disabled="#{myBean.checkedSelectOneRadioValue eq 'TEST'}" />
</h:inputText>
Replace the renderattribute content with the real id of your input field with the validator. This assumes that the selectOneRadio and the inputText are inside the same NamingContainer.
To avoid extended discussions in comments, i will provide my suggestions as an answer to discuss it further...
At first it should be
disabled="#{myBean.checkedSelectOneRadioValue == 'TEST'}
or
disabled="#{myBean.checkedSelectOneRadioValue eq 'TEST'}
Additional, at least in ICEFaces (and MyFaces should have this function, too), you may use:
<h:selectOneRadio value="#{myBean.checkedSelectOneRadioValue}" partialSubmit="true">
<f:selectItems value="#{myBean.valuesForSelectOneRadio}" />
</h:selectOneRadio>
This should force an ajax request after changing the value of selectoneradio and the validator-disabled check should be able to get it from the bean.
If that does not work, there may be autoSubmit or similar in MyFaces...

AJAX onSubmit validation in JSF 2.0

I've started learning JSF2.0, and have come across a problem. Any advice on how to proceed would be welcome.
I have renamed form elements and classes for simplicity sake.
I have a form, for example:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}"/>
<div id="dataPoint1Error" class="msgError">Value not found in database.</div>
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}"/>
<div id="dataPoint2Error" class="msgError">Value not found in database.</div>
<h:commandButton action="#{bean.validate}" type="submit" value="Search"/>
</h:form>
The CSS class "msgError" keeps the element hidden by default.
I would like to basically have a method in the "bean" class that validates the input by checking against the database, then if the value isn't found, unhide the error message, or if it is found, then execute another method which performs the actual functionality.
In my head, it would work sort of like this in the Java (forgive any syntax errors, just typing as I think):
#ManagedBean
public class Bean {
private String dataPoint1 = "";
private String dataPoint2 = "";
public boolean validate() {
if(dao.fieldExists(this.dataPoint1) && dao.fieldExists(this.dataPoint2)) { //check the database
performFunctionality();
return true;
}
else {
return false; //and show error div on screen
}
}
public void performFunctionality() {
//do whatever
}
//getters and setters
}
Any advice would be very welcome!
Thanks!
You're not utilizing JSF builtin validation facilities. Make use of it.
Here's how it can look like:
<h:form id="frmSearch">
<h:inputText id="dataPoint1" value="#{bean.dataPoint1}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint1" />
<h:inputText id="dataPoint2" value="#{bean.dataPoint2}" validator="#{bean.validateDataPoint}" />
<h:message for="dataPoint2" />
<h:commandButton action="#{bean.performFunctionality}" value="Search">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
with
public void validateDataPoint(FacesContext context, UIComponent component, Object convertedValue) {
if (!dao.fieldExists((String) convertedValue)) {
throw new ValidatorException(new FacesMessage("Value not found in database."));
}
}
That performFunctionality() must be executed by the command button's action method.
When validation fails (i.e. ValidatorException is been thrown), then the message will be displayed in the <h:message> associated with the input component and the action method won't be invoked. The validator attribute can alternatively also point to a fullworthy class which implements javax.faces.validator.Validator. The <f:ajax> is been added to make it an ajax submit.
See also:
How to perform validation in JSF, how to create a custom validator in JSF
Wherever you've learnt JSF, make sure that you've also read the chapters about conversion and validation. Don't think too much the PHP/ASP/JSP/jQuery way. JSF is a full fledged component based MVC framework.

Resources