Struts2 AJAX validation doesn't stay on page - ajax

I've been trying for a few days now to make Struts2 AJAX validation work but I can't solve one last problem. I'm using the struts2jquery plugin to asynchronously submit my form:
<div id="result"></div>
<s:form action="RegisterUser" theme="xhtml" method="post">
<s:textfield key="firstname" label="First name" size="35"
required="true" />
<s:textfield key="lastname" label="Last name" size="35"
required="true" />
<s:textfield key="address" label="Address" size="35"
required="true" />
<s:textfield key="phone" label="Phone number" size="35" />
<s:textfield key="username" label="Username" size="35"
required="true" />
<s:password key="password" label="Password" size="35"
required="true" />
<s:textfield key="email" label="E-mail address" size="35"
required="true" />
<sj:submit key="Inregistrare" targets="result" align="right"
button="true" validate="true" onSuccessTopics="notifyRegistration" />
</s:form>
I've included the required scripts:
<script type="text/javascript" src="./js/registerScript.js"></script>
<!-- This files are needed for AJAX Validation of XHTML Forms -->
<script src="${pageContext.request.contextPath}/struts/utils.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/struts/xhtml/validation.js"
type="text/javascript"></script>
and the tag:
<sj:head jqueryui="true" />
The onSuccess handler:
$(document).ready(function(){
$.subscribe('notifyRegistration', function(event,data) {
var registrationStatus = event.originalEvent.data.registrationStatus;
if(registrationStatus == 'SUCCESS'){
alert('Contul dumneavoastra a fost creat cu success!');
window.location.href = "./index.html";
} else {
alert('Contul dumneavoastra nu a putut fi creat. Va rugam incercati din nou.');
}
});
});
My configuration looks like this:
<action name="RegisterUser" class="actions.Register" method="execute">
<interceptor-ref name="jsonValidationWorkflowStack"/>
<result name="input">/pages/Register.jsp</result>
<result type="json"/>
</action>
And the execute method of my action class:
public String execute() throws Exception {
if (isInvalid(getUsername()) || isInvalid(getPassword())
|| isInvalid(getEmail())) {
registrationStatus = REGISTRATION_ERROR;
}
if (registerUser()) {
registrationStatus = REGISTRATION_SUCCESS;
return SUCCESS;
}else {
registrationStatus = REGISTRATION_ERROR;
}
return SUCCESS;
}
The registerUser() method makes the actual insert into the database. The validation XML is called Register-Validation.xml.
The validation works fine - if some fields are not filled in, it shows the error labels without refreshing the page. My problem is that even is the action returns SUCCESS or ERROR, the browser displays the JSON that it sent back on another page, ../Register.action. I have no idea why it doesn't enter my onSuccess handler. I've successfully used AJAX on other forms, the only difference here is that I use the validation xml and the jsonValidationWorkflowStack interceptor. Why is this happening and how can I avoid being redirected? Why doesn't the request reach the onSuccess handler?

Do you have getters for registrationStatus in your Action ?
I would put an alert(event.originalEvent.data.registrationStatus); in your notifyRegistration callback function, just to see what is its value.
By the way, it seems that you have mixed
Struts2-jQuery Plugin AJAX Form Validation with Struts2 XHTML Theme
with
Struts2-jQuery Plugin: Remote Link that handle an JSON Result with an onSuccessTopic
AFAIK (but I've never used this specific kind of validation), the validation should not be handled in execute(), but in validate() or through XML, or with Annotations.
The example in Struts2-jQuery Plugin showcase uses Annotations, but you can easily transform it in XML and try the showcase.
You would have no need to use the javascript function nor the onSuccessTopic at all, following the example.
You can run it in the showcase too, under Forms -> Forms with Validation (but stick to the documentation for the code, because the code in the showcase seems to miss some pieces... for example the validation against "test" password).

Related

JSF ajax render message and redirect

I have a JSF application where users login in a login form inserting their email and password. The ManagedBean has the following 2 methods.
The method checkIdentity1() returns an URL ("" if the validation is incorrect in order to stay in the same page, or /useraccount.xhtml if inserted data is ok in order to go to next page).
The method checkIdentity2() returns a boolean value (false if the validation is wrong in order to show a message, true if it is ok).
loginManagedBean.java
public String checkIdentity1()
{
String strResponse="";
//check id
if(email.equals("jose#a.com") && password.equals("1234"))
{
strResponse="/useraccount.xhtml?faces-redirect=true";
} else {
}
//
return strResponse;
}
public boolean checkIdentity2()
{
boolean bResponse=false;
//check id
if(email.equals("jose#a.com") && password.equals("1234"))
{
//setpassIncorrecta(false);
} else {
bResponse=true;
}
//
return bResponse;
}
What I am trying to do is to mix ajax and JSF to show "Email and/or password incorrect" when I click Login button and validation fails and go to account.xhtml when validation is ok. But when I insert incorrect email and password no message is displayed, and when I insert them correctly the page is no redirected to account.xhtml. What am I doing wrong?
This is my Facelet
<h:form>
<!--Email-->
<h:inputText id="email" label="email" required="true" size="32" maxlength="32"
value="#{loginManagedBean.email}"
requiredMessage="Insert your email">
</h:inputText>
<h:message for="email" />
<!--Password-->
<h:inputSecret id="password" label="password" required="true" size="32" maxlength="40"
value="#{loginManagedBean.password}"
requiredMessage="Insert your password">
</h:inputSecret>
<h:message for="password" />
<!--Button-->
<h:commandButton value="Login" action="#{loginManagedBean.checkIdentity1()}">
<f:ajax execute="#form" render=":loginErrorMessage" />
</h:commandButton>
</h:form>
<h:panelGroup id="loginErrorMessage">
<h:outputText value="Email and/or password incorrect" rendered="#{!loginManagedBean.checkIdentity2()}" />
</h:panelGroup>
Like I explained in the comment, that's just the way JSF works: if a request fails validation, the action method will not be executed. That's defined the JSF request processing lifecycle (which I won't get into here). For the purpose of this answer, all you need to know is that the validation of request parameters happens before the action methods are considered. That being said, if the validation fails, the request processing is short-circuited there and then. To achieve what you're looking for, you should consider the following:
To conditionally render that component, you can examine the validation status in your page:
<h:outputText value="Email and/or password incorrect" rendered="#{facesContext.validationFailed}" />
Ideally, you should just use the <h:messages/> component, where you don't need to manage message display yourself
JSF will stay on the same page by default, if the validation fails, so you needn't take any special steps to that effect

how to check existing user in a database with Struts and Ajax

I want to verify if an email exists in my database before form submission:
<form action="add" method="post">
<input type="text" name="user.email" />
<input type="submit" value="Ajouter" />
</form>
How can I use Ajax to check if the email exists already in the database before submitting?
You can use the Validate() method when you extends the ActionSupport calls in your Controller ; then you check your email and return an ActionFieldError if it dosent' exist.
it's simple:
public void validate() {
if(!emailExist(this.email)){
addFieldError(email, "Email already exist;You must choose another one"); }
}
That assumes that you have a field with the name ="email" and a function that check mail existence called emailExist(String mail)
If you really want ajax validation , you can use Struts2 jQuery Plugin and you instead of :
<s:submit />
you make something like this:
<sj:submit
targets="result"
button="true"
validate="true"
value="AJAX Submit"
indicator="indicator"
/>

How to customize the presentation of faces messages

I would like to customize the presentation of faces messages.
For this,
<h:inputText id="name" required="true" />
when validation is failed, then it will be shown in a
<h:message for="name" />
However, I would like to customize the presentation call JS as follows:
<div class="notification"></div>
function showNotification(msg){
$(".notification").html(msg);
$(".notification").fadeIn(1000, function(){
timeout = setTimeout(function(){
$(".notification").fadeOut(1000);
}, 5000);
});
}
How can I achieve this?
You can use FacesContext#getMessageList() to get the messages in the view, if necessary the ones for a specific client ID. You can iterate over them in a ui:repeat. Each item is a FacesMessage which has several getters. You can display any HTML in the message unescaped by using <h:outputText escape="false">.
So, in a nutshell:
<ui:repeat value="#{facesContext.messageList('form:name')}" var="message">
<div><h:outputText value="#{message.summary}" escape="false" /></div>
</ui:repeat>
(in the above example, I assume that your form has id="form")
Or, if that HTML help link is actually not part of the message, then so:
<ui:repeat value="#{facesContext.messageList('form:name')}" var="message">
<div>#{message.summary} help</div>
</ui:repeat>

How to execute code after the jquery.validate validation event?

I am using jquery.validate 1.9 and wish to execute code every time the form automatically validates (using the default behavior).
I hoped there would exist an OnValidated event I could hook into, but can not find one.
After validation executes I wish to conditionally enable other parts of the page if the form is valid, and disable otherwise.
How would one go about adding a method call following the existing validate() function?
I'm using jquery validate 1.8.1, but you should still be able to accomplish this using the valid() function.
valid() will either validate the entire form if you pass it the form ID or individual fields if you pass their respective ID's. It will then return a Boolean based on if they are all valid or not.
Something like this should work:
<script type="text/javascript">
function tab1Validation(){
if($('#field1, #field2, #field3').valid()){
//Logic if all fields valid - eg: $('#NextTab').show();
}else{
//Logic if one or more is invalid
}
}
</script>
<form id="yourform">
<div>
<input type="text" id="field1" name="field1" />
<input type="text" id="field2" name="field2" />
<input type="text" id="field3" name="field3" />
</div>
<input name="nextTab" type="button" value="Next Tab" onClick="tab1Validation();" />
</form>

Can I load the max value of the range attribute in CFINPUT using and AJAX call?

I have a CFINPUT tag in a CFFORM. I want to set the range dynamically without posting the page. I have several AJAX calls throughout the page to dynamically load form fields on the fly:
<cfselect id="this" name="this" bind="cfc:Data.getThis()" bindonload="true" />
<cfselect id="that" name="that" bind="cfc:Data.getThat({p1})" />
<cfselect id="theOther" name="theOther" bind="cfc:Data.getTheOther({p1}, {p2})" />
<cfdiv
id="maxQty"
bind="cfc:Data.getMaxQty({itemId})" />
<cfinput
type="text"
id="qty"
name="qty" />
<cfdiv
id="itemId"
bind="cfc:Data.getItemId({this}, {that}, {theOther})" />
In the above CFFORM, I basically want to set the minValue of the range to "1" and the maxValue of the range to the value of cfc:Data.getMaxQty({itemId}).
Is this possible? How can I do it?
The quick answer is "No". But there is a very easy workaround. Simply load the value that you want to be the maximum into a CFDIV or a CFINPUT hidden field using binding, then access that value in a JavaScript function that validates the min/max values when you submit the form:
<script type="text/javascript">
<!--
function validateForm() {
var maxQty = document.getElementById("maxQty").innerHTML;
if (document.myForm.add_item_1.value < 1 || document.myForm.add_item_1.value > maxQty) {
alert("Quantity must be an integer value between 1 and " + maxQty);
return false;
}
return true;
}
//-->
</script>
<cfform name="myForm" method="post" action="myFormAction.csm" onsubmit="return validateForm();">
<cfdiv
id="maxQty"
bind="cfc:Data.getMaxQty({itemId})" />

Resources