Ajaxified SelectOneListBox not working [duplicate] - ajax

This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 5 years ago.
I wanted to test if an ajaxified <p:selectOneListBox> element works fine or not. On a JSF+PrimeFaces based portlet I've created the above code. Basically, on a item selection from a <p:selectOneListBox> list, I want to update a label with the value of the previously selected item. Unfortunately, it doesn't seem to work as expected.
.xhtml side:
<form id="myform">
<p:selectOneListbox id="myselect" value="#{bean.optionSelected}">
<p:ajax listener="#{bean.onChange}" process="myselect" update="toupdate" onstart="onstart()" oncomplete="oncomplete()" onerror="onerror()" onsuccess="onsuccess()"/>
<f:selectItem itemLabel="Option 1" itemValue="1" />
<f:selectItem itemLabel="Option 2" itemValue="2" />
<f:selectItem itemLabel="Option 3" itemValue="3" />
</p:selectOneListbox>
<h:outputText id="toupdate" value=">#{bean.optionSelected}" />
</form>
Bean side:
#ManagedBean(name = "bean")
#ViewScoped
public class Bean implements Serializable {
private static final long serialVersionUID = 201709131528L;
private static Logger logger = Logger.getLogger(Bean.class);
private String optionSelected = "-1";
public Bean() {
logger.trace("bean created");
}
#PostConstruct
private void onPostConstruct() {
logger.trace("start");
}
public String getOptionSelected() {
return this.optionSelected;
}
public void setOptionSelected(String optionSelected) {
logger.trace("start");
this.optionSelected = optionSelected;
}
public void onChange() {
logger.trace("start");
}
}
Every time I select an option from the list I've got the following log from the console:
Bean:<init>():bean created
Bean:onPostConstruct():start
And from the console of my browser I've got the following log:
onstart():
onerror():
oncomplete():
As a newcomer to the JSF+PF world, I'd like to know:
1) why the onChange() listener is not invoked.
2) why the property optionSelected is not set.
3) why the bean bean is created on each option selection.
4) why the ajax request fails.
Any clarification would be really apreciated. Thanks.

As a newcomer to the JSF+PF world, I'd like to know: 1) why the onChange() listener is not invoked. 2) why the property optionSelected is not set. 3) why the bean bean is created on each option selection. 4) why the ajax request fails.
I believe all of your issues are caused by the fact that you are using an html <form> element rather than a JSF <h:form> component. I was able to reproduce all these errors locally on my machine (except #4 for some reason), and once I changed the <form> into an <h:form>, everything worked correctly.
For more information on what the JSF h:form tag does, check out these links:
https://docs.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/h/form.html
https://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/api/javax/faces/component/html/HtmlForm.html
What exactly does JSF h:form tag
How to use <f:ajax> in a plain <form> instead of <h:form>?
How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?

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

Richfaces Datatable loses submitted value of inputs on validation fail

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.

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.

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