Our team is writing its first JSF 2.0 application since using Stripes for many years, and I have some questions on the best way to use the f:ajax tag and validate the input.
A lot of questions I've seen answered have a form with multiple inputs and then a submit button), but we would like to maintain individual input fields updated immediately upon change and persisted to the database (with no submit button. We had this working fine in Stripes using Prototype's Ajax.Request, but it was an extra step I'd like to avoid if possible.
Essentially we have a page with a bunch of inputs on it directly backed by beans, for example:
<h:inputText id="name" value="#{personController.name}" >
<f:ajax listener="#{personController.ajax}" />
</h:inputText>
As you may know, by the time the listener is invoked, the value of name has already been changed on the bean. This would be convenient, but I have a few problems with it:
the listener doesn't obviously know which value of the bean was changed
the value has already been changed, I can't perform any server side validation on it
I don't know what the old value of name is even if I could perform some sort of validation on it, I wouldn't know what to set the value back to
Right now it's looking like we'll have to implement some kind of javascript middleman to take in what property changed and the new value, send that to the Controller, and have it perform validation, updating the database, sending back something to render, etc. But like I said, this is what we used to do with Stripes and I'd really like to use something more native.
I did see that if we wanted some kind of Submit button on the page we could use something like the valueChangeListener attribute, but I'd also like to avoid massive submits.
I included the OpenFaces tag because we're already using that for datatables, so if there's something nice in there we're open to using it. But as far as I can tell their o:ajax tag isn't that much more powerful than JSF's f:ajax.
Thanks!
You're looking in the wrong direction to achieve the concrete functional requirement of validating an input field. You should use a normal JSF validator for this, not some ajax listener method which runs at the wrong moment (the INVOKE_ACTION phase instead of PROCESS_VALIDATIONS phase) and where you don't directly have a hand at the model value. The ajax listener method is merely to be used to execute some business logic based on the current model value(s).
JSF has several builtin validators behind the required attribute and several <f:validateXxx> tags. You can even create custom validators by implementing the Validator interface.
E.g. checking the requireness:
<h:inputText ... required="true">
<f:ajax />
</h:inputText>
Or checking if it matches a pattern using one of the various <f:validateXxx> tags:
<h:inputText ...>
<f:validateRegex pattern="[a-z]+" />
<f:ajax />
</h:inputText>
Or using a custom validator:
<h:inputText ...>
<f:validator validatorId="myValidator" />
<f:ajax />
</h:inputText>
with
#FacesValidator("myValidator")
public class MyValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) {
if (value is not valid) {
throw new ValidatorException(new FacesMessage(...));
}
}
}
The <f:ajax> is merely there to submit the current input field during the HTML DOM change event (or click event in case of checkboxes/radiobuttons). You don't necessarily need a <f:ajax listener> method in order to submit the current input field by ajax. If you want to hook on a value change event, just use valueChangeListener.
<h:inputText ... valueChangeListener="#{bean.valueChanged}">
<f:ajax />
</h:inputText>
with
public void valueChanged(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getValue();
UIComponent component = event.getComponent();
// ...
}
Note that this will only be invoked when validation has passed on the particular component.
Related
I have this simple facelets page:
<!DOCTYPE html>
<html xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Index</title>
</h:head>
<h:body>
<h:form>
<h:inputText id="firstname" value="#{fooBar.firstname}">
<f:ajax event="keyup" render="echo" execute="myCommandButton"/>
</h:inputText>
<h:commandButton value="Submit" action="#{fooBar.fooBarAction()}" id="myCommandButton"/>
</h:form>
<br/>
<h:outputText id="echo" value="#{fooBar.firstname}"/>
</h:body>
</html>
and the Foobar bean is as follows:
#ManagedBean
#ApplicationScoped
public class FooBar {
private String firstname;
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getFirstname() {
return firstname;
}
public void fooBarAction() {
System.out.println("Foo bar action being executed!!!");
}
}
So my expectation is to see the text Foo bar action being executed whenever I type something in the inputText field, but it is not the case. What am I missing?
Edit: Why am I expecting this behavior?
I am studying the book Core JavaServer Faces and in the book it is noted that:
JSF 2.0 splits the JSF life cycle into two parts: execute and render.
Execute consists of: Restore View -> Apply Request Values -> Process
Validations -> Update Model Values -> Invoke Application
When JSF executes a component on the server, it:
-Converts and validates the component 's value (if the component is an input).
-Pushes valid input values to the model (if the component is wired to a bean property).
-Executes actions and action listeners (if the component is an action).
So here, myCommandButton should be executed, isn 't it? And execution of a component means its action to be executed?
Edit #2
This quotation is from JavaServer Faces Complete Reference
If listener is not specified, the only action that will be invoked
during the Invoke Application phase will be the one that corresponds
to an ActionSource component listed in the execute attribute.
So as far as I understand, in my example, I have a component that implements the ActionSource interface (myCommandButton), and the action attribute of this component should be executed. But it is not?
The execute attribute of <f:ajax> basically tells JSF which components to process through the JSF lifecycle during the postback. I.e. it basically tells JSF for which components it must execute the apply request values, process validations, update model values and invoke application phases. The apply request values phase will collect (decode) submitted HTML form (input and button) values. The validations phase will run conversion/validation on submitted values. The update model values phase will set submitted/converted/validated values in backing bean. The invoke application phase will execute the submitted action. Note that the key is that JSF will do this all based on submitted HTML form values.
In other words, the execute attribute is entirely server side. It is not client side as you seemed to expect. You seemed to expect that it tells the webbrowser to submit the specified component, as if you were clicking on it. This is not true. The button value is only processed through the JSF lifecycle when it was actually being pressed/clicked/submitted.
If the button is specified in execute attribute and JSF determines during processing the lifecycle that the button value is actually not submitted (i.e. it is entirely absent in HTTP request parameter map), then JSF won't queue the action event during apply request values phase at all. And therefore nothing will be invoked during invoke application phase.
When the <f:ajax> event is triggered, it's actually the enclosing component which is the action source. You should therefore hook the desired action listeners on it. You can use listener attribute of <f:ajax> for that.
<h:form>
<h:inputText id="firstname" value="#{fooBar.firstname}">
<f:ajax event="keyup" listener="#{fooBar.keyupListener}" render="echo" />
</h:inputText>
<h:commandButton value="Submit" action="#{fooBar.fooBarAction}" id="myCommandButton"/>
</h:form>
#ManagedBean
#RequestScoped
public class FooBar {
private String firstname;
public void keyupListener() {
System.out.println("Keyup listener being executed");
}
public void fooBarAction() {
System.out.println("Foo bar action being executed");
}
// ...
}
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
How does JSF process action listener?
The action and/or actionListener you want to call on each key stroke have to be defined in the f:ajax facet. You defined your action in the h:commandButton below. JSF doesn't see any connection between the ajax facet and the button. Apart from technical reasons, there are at least two reasons making this behaviour plausible:
You can have multiple command buttons in your form. In fact, more often than not you have at least two: "save" and "cancel". Should both actions be triggered on every key stroke? In which order? There's no way to decide that automatically, so JSF decides to avoid this problem by forcing you to define the action within the AJAX facet. Mind you: Your form might contain a table consisting of 100 rows, each with a "delete", "edit", and "insert new row after this row" button. Which action should be executed?
The input field may have multiple f:ajax facets. For example, you can define different facets for the events "keyup" and "blur". If you define multiple facets, you probably want them to call different backend bean methods. You do not want them to call any other command button of the form. Remember, it might be the "cancel" button, which is a bit inconvenient if it's triggered on each key stroke.
So the statement you've quoted from the Core JSF book is correct. Every action and actionListener is executed. Your mistake is that you've mentally expanded the scope to the entire form. Instead, JSF only looks at the component surrounding the AJAX facet.
The quotation of the JavaServer Faces Complete Reference simply sounds wrong to me. When neither an action nor an actionListener is specified, the "invoke application" phase of JSF doesn't do anything. The input is sent to the server, it is validated, it is stored in the backend bean and it's used to render the page again. But no action is called because you didn't specify an action to be called.
I have currently implemented this functionality with onkeypress event with pure javascript.
There is a textarea field. As soon as the user keys something, the implemented functionality shows him/her about how many characters are remaining.
Now the customer is demanding that the same to be done with validators in JSF? No Javascript.
I am confused as how will I invoke a validation method on every keypress event with JSF?
Kindly suggest something?
EDIT:
I am not sure on this one,
<f:ajax event="keypress" listener="#{helloBean.validateLength}">
<h:inputTextarea value="#{helloBean.name}"></h:inputTextarea>
</f:ajax>
with listening method,
public void validateLength(AjaxBehaviorEvent event) {
// stuff
}
But it javscript is disabled, will this work?
Keep your JavaScript to display remaining chars. That's indeed not a real validator, but it's just an helpful indicator for which a JSF based solution would be really expensive.
To force the textarea's maxlength in client side, use the new HTML5 maxlength attribute on the component.
<... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputTextarea ... a:maxlength="1000" />
Hint: you can make use of it in your "Remaining chars" script to make it more generic/reusable by just letting it extract the maxlength from the HTML DOM.
Then, to validate actual maximum length in server side, just use either JSF's <f:validateLength>.
<h:inputTextarea ...>
<f:validateLength maximum="1000" />
</h:inputTextarea>
Or BV's #Size.
#Size(max=1000)
private String text;
Either way, you can trigger server side validation during keyup event by simply nesting <f:ajax event="keyup"> inside the textarea.
<h:inputTextarea id="text" ...>
<f:ajax event="keyup" render="m_text" />
</h:inputTextarea>
<h:message id="m_text" for="text" />
But as said, that's really expensive. Even if you used <f:ajax delay>, I'd still not recommend that and just leave it out. It has no true benefit here as the maxlength already restricts the maximum length in the client side.
All in all, I hope you learnt to use a normal validator in case you want to perform validation, and not try to abuse an action(listener) method for that. See also JSF 2.0 validation in actionListener or action method.
I am currently working on a primefaces webapp and I have the following problem:
I create p:inputText fields dynamically inside an ui:repeat. There is a list with users and for each user an input can be made. To keep track of this input-to-user-mapping I had to use a map to use key-value pairs. As soon as a input for one of the users is made, a action needs to be called on the blur event. This is no validation, but a kind of calculation which influences the other inputfields.
My problem is, that the action is not getting called, if the input field was created by the ui:repeat.
I hope I illustrated the problem properly. Please see the code below. Does someone knows a workaround or solution for this? Maybe there is another way to implement this usecase, but I am not aware of it.
edit1: I added the backing bean. As I dont know which method needs to be called, I made a little overloading. Other components (commandbuttons and others) work well with the xhtml and the backing bean, so I removed them for a cleaner structure.
edit2: I found out, that if I replace the value of the p:inputText #{user.value} to something static like e.g. #{bean.value123} it works! So the problem seems to be with the var attribute?
My xhtml:
<h:form id="myForm">
<ui:repeat var="user" value="#{bean.userForInputs.entrySet().toArray()}">
<p:inputText value="#{user.value}">
<p:ajax event="blur" listener="#{bean.updateMethod}" process="#this"/>
</p:inputText>
</ui:repeat>
</h:form>
My backing bean:
public void updateMethod(final AjaxBehaviorEvent event) {
System.out.println();
}
public void updateMethod() {
System.out.println();
}
I have an input textbox that accept a name, process the name in reverse order, and then output it to another textbox. Whenever I input the value and click anywhere on the page (means lost focus from textbox), the output textbox will get update automatically.
When I open up the source code I found something like code below, may I know what does the ajax thing do to the inputtext component?
<h:inputText id="name" value="#{helloBean.name}">
<f:ajax render="printMyName"/>
</h:inputText>
<h:outputText id="printMyName" value="#{helloBean.reverseName}"/>
Taken from Learning JSF2: Ajax in JSF – using f:ajax tag
Sending an Ajax request
JSF comes with one tag to send an Ajax request, the tag is called
f:ajax. This tag is actually a client side behavior. Being a behavior
implies it’s never just used by itself on a page, it is always added
as a child tag (behavior) to another UI component (or can even wrap
several components). Let’s use a small echo application to demonstrate
usage of this tag.
<h:form>
<h:panelGrid>
<h:inputText value="#{bean.text}" >
<f:ajax event="keyup" render="text"/>
</h:inputText>
<h:outputText id="text" value="#{bean.text}" />
</h:panelGrid>
</h:form>
Code snippet above takes care of firing an Ajax request based on onkeyup event. Notice the actual event name is keyup. This takes care of firing an Ajax request. Next we need to figure out how to do partial view rendering.
Attribute Description event:
String on which event Ajax request will be
fired. If not specified, a default behavior based on parent component
will be applied. The default event is action for ActionSource (ie:
button) components and valueChange for EditableValueHolder components
(ie: input). action and valueChange are actual String values that can
be applied applied event attribute.
I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
How to select JSF components using jQuery?
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable ids, which are incompatible with css part of web standards