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.
Related
I have a complex page with a p:commanButton with actionListener and immediate="true"
Upon clicking this commandButton, I need to process a single inputField(thus skipping rest of the form). The problem is, that the inputField has a validator which I'd like to use only in full page submit.
<p:inputText id="#{cc.attr.id2}_input" value="#{myBB.value}"
immediate="true">
<f:validateLength minimum="4"/>
</p:inputText>
<p:commandButton id="#{cc.attr.id2}_search" immediate="true"
process="#{cc.attr.id2}_input #this"
actionListener="#{myBB.listener}">
</p:commandButton>
When I do this with i.e. 3 letters in the inputText, the myBB.value is not updated because of the failed validation. So I'd like to disable the validator for the inputField for the immediate processing by the commandButton. But I don't know how.
I know I can get the value from the ExternalContext, but this seems like a very hacky solution to me(and in my case is not even applicable, because it's inside composite component and I have no way of knowing the clientId of the textField.)
I also know about disabled attribute of the validator tag, but I have no idea how could I put that to use in this situation.
EDIT: I've changed a code a bit, because the IDs I'm using are actually not as simple as I first stated and don't allow me to use simple proposed solution.
I use Mojarra 2.2.4 and Primefaces 4.0
So, first of all, you haven't got the problem with immediate, but rather with <f:validateLength> validator.
That is, to rephrase your question, you'd like to skip validation of a given component in case the particular button is clicked.
Depending on whether you are on Mojarra 2.1.18+ or not there are two solutions. The first one is quite straightforward: use the disabled attribute of <f:validateLength>, while the other one takes into account issue 1492. As we've nowadays have advanced past the aforementioned version of Mojarra, I'll post the first and easier solution, otherwise, scroll through the excellent answers to Why does f:validateDoubleRange only work for #SessionScoped? and Disabled attribute of <f:validateLength> does not evaluate request parameters by BalusC.
So, the solution is the following:
<h:form id="formId">
<p:inputText id="inputId" value="#{myBB.value}">
<f:validateLength minimum="4" disabled=#{not empty param['formId:buttonId']}" />
</p:inputText>
<p:commandButton id="button" process="#this inputId" actionListener="#{myBB.listener}" />
</h:form>
As a side note, you can see that I didn't use immediate attribute at all because I supposed that you abused it to perform a given task. With the rise of AJAX in particular within JSF-based applications you can now easily group a subset of input elements validation by specifying the process attribute of <p:commandButton> or <p:ajax> instead of the previously used prioritized validation especially in synchronous requests. Only those components whose ids are supplied will be processed on the server and all other components will be omitted prom processing lifecycle. Also note that process="#this ..." is also mandatory to execute actions associated with the button itseld.
Regarding the appropriate usage of immediate I'd strongly suggest to refer to the classics: Debug JSF lifecycle blog post by BalusC to check whether you've used it correctly.
I have a form in the view "createDbUser.xhtml" with some input texts and validations like this:
<h:form>
<h:inputText id="user_name" value="#{dbUserManager.userName}" required="true" requiredMessage="User name is required." />
<h:inputSecret id="password" value="#{dbUserManager.password}" required="true" requiredMessage="Password is required." />
<h:commandButton id="create_user" value="Create user" action="#{dbUserManager.createUser()}" />
</h:form>
dbUserManger is a viewScoped managed bean with createUser() like this:
public String createUser()
{
...
// here I do some checks and add the new user to database
...
return "/restricted/createDbUser.xhtml?faces-redirect=true";
}
When I press the refresh button of my browser while some of the validations failed (e.g. I didn't enter password or username), I got "confirm form resubmission" instead of expected behaviour, i.e. reloading the page and clearing the inputs.
I've read about post-redirect-get pattern and that's why I added the return statement with "faces-redirect=true" parameter to the outcome of createuser().
I guess when validation failed we never get to the createuser() and consequently the return statement. And that's the cause of this problem. But I don't know how to solve it.
It would be very nice if some one help to solve the issue.
thanks
you are right:
When validation errors are recognized on server side during JSF LifeCycles Validation Phase, your action method is never called (being in the invoke phase later on).
What I would see as possible solutions: Try doing the validation client-side - for e.g. checking if login/pw exists, this could be achived via javascript triggered by h:commandButtons onclick-attribute. I'm not sure if you use any *Faces-framework above JSF2, but e.g. Richfaces4 also allows clientside validation without changing any code.
Another possible solution might be to send the form via AJAX, changing
<h:commandButton action="#{dbUserManager.createUser()}" />
to something like
<h:commandButton action="#{dbUserManager.createUser()}">
<f:ajax execute="#form" render="#all" />
</h:commandButton>
Here you might need to figure out how to manage the redirect to another screen in case of a correct login.
Hope, these ideas might push you further towards achieving your goals...
The supported JSF 2.x feature of sequential processing of multiple ajax-events doesn't work for me.
I got the following scenario:
h:inputText (CHANGE)
<h:inputText id="consumption_input"
value="#{cc.attrs.consumptionInfo.consumption}">
<f:ajax
render="#{cc.attrs.outerRenderString}"
event="change" listener="#{cc.handleAjaxRequest}" />
</h:inputText>
h:commandButton (ACTION)
<h:commandButton
id="startComparisonButton"
action="#{rateComparisonBean.startRateComparison()}"
value="#{bundle.rateResultOverview_startComparison}">
<!-- This is to avoid mixed requests, ajax and full requests -->
<f:ajax render="#form"/>
</h:commandButton>
The events of both elements are handled correctly if triggered on it's own.
Problem occurs when both events are triggered within one click (Enter a value in textInput and afterwards click on the button). I expected this lead to two ajax request fired synchronously (CHANGE-TextField and ACTION-commandButton).
Unfortunatelly there's only one Ajax-Request (Change-TextField), the second event seems to be lost completely.
I already ensured that all pre-conditions for a h:commandButton are full filled, as pointed out here:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I would appreciate to get any hints on how to solve this problem.
Environment:
Glassfish 3, Mojarra 2.1.3-FCS
The JSF AJAX calls are asynchronous. Sending one AJAX request, in this case generated by <h:inputText> onchange event, doesn't stop JavaScipt to continue its execution and, in this case, trigger submit button click, which in its turn fires another AJAX request. Still, AJAX requests are really queued on the client, to be processed in the exact order that they were sent, which is guranteed by JSF 2.0 specification, chapter 13.3.2.
Below is my test case:
The view:
<h:form id="form">
<h:inputText id="text" value="#{q16363737Bean.text1}">
<f:ajax render="text2" event="change" listener="#{q16363737Bean.ajaxListenerText}"/>
</h:inputText>
<h:commandButton id="button" action="#{q16363737Bean.actionButton}" value="Submit">
<f:ajax render="text1 text3" listener="#{q16363737Bean.ajaxListenerButton}"/>
</h:commandButton>
<br/>
<h:outputText id="text1" value="Text 1: #{q16363737Bean.text1}."/>
<h:outputText id="text2" value="Text 2: #{q16363737Bean.text2}."/>
<h:outputText id="text3" value="Text 3: #{q16363737Bean.text3}."/>
</h:form>
The bean:
#ManagedBean
#ViewScoped
public class Q16363737Bean implements Serializable {
private String text1 = "I'm text 1";//getter + setter
private String text2 = "I'm text 2";//getter + setter
private String text3 = "I'm text 3";//getter + setter
public void ajaxListenerText(AjaxBehaviorEvent abe) {
text2 = "I was modified after inputText AJAX call";
}
public void ajaxListenerButton(AjaxBehaviorEvent abe) {
text1 = "I was modified after AJAX listener call of commandButton";
}
public void actionButton() {
text3 = "I was modified after commandButton AJAX call";
}
}
After examining the question for some time I indeed figured out that very rarely the command button's AJAX call had been swallowed and no UI updates were done. It seems that there should be some race conditions somewhere. It is a great question and it needs to be investigated further.
So, this is probably not an answer (although I thought it would be initially), but a proposition for a test case. And despite the fact that I faced this behaviour very infrequently, it is a real use case, and it's worth fully understanding what's going on.
First thanks allot for the fast and sophisticated reply.
A second test from the scratch pointed out that ajax-events are queued properly.
So again I checked the more complex scenario described above. The cause for the skipped event seams to be related to our 'busy overlay'. Think of it as a bunch of JavaScript which disables form-elements and applies an overlay during long runing ajax requests. This is done by applying an jsf.ajax.addOnEvent call-back.
Anyway, even we disable some controls, after 'success' the form is in a proper state and the second event could be handled.
Currently I assume that the 'temporarily' disabled button compromises the related action event which should be carried out afterwards.
We are currently analyzing the issue and I will post the final result asap.
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.
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.