Struts ajax form validation - json

i have a problem with ajax form validation. I'm using struts-core 2.3.1.2, struts-jquery-plugin 3.3.0 and struts-json-plugin.
The problem occurs if an ajax form will be submitted by an ajax request and validation fails. Cause then the whole form will be placed on the result element. Therefore you can activate ajax validation on the ajax sumbit button.
http://code.google.com/p/struts2-jquery/wiki/Validation
Here are also outdated information:
http://struts.apache.org/2.2.3.1/docs/ajax-validation.html
But the interceptor "jsonValidationWorkflowStack" is missing in struts-default.xml like written in post: jsonValidationWorkflowStack seems to be removed in Struts 2.3.1
It is sourced out to the struts-json-plugin in struts-plugin.xml. I don't know how i can use this directly but i build my own Stack in struts.xml:
<!-- Sample JSON validation stack -->
<interceptor-stack name="jsonValidationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="jsonValidation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
</interceptors>
<action name="updateMySettings" method="execute" class="de.ra.daod.actions.MyAppSettingAction">
<interceptor-ref name="jsonValidationWorkflowStack"/>
<!-- This is not beauty within ajax -->
<result name="input">/WEB-INF/jsp/mysetting_ajax.jsp</result>
<result name="success" type="stream">
<param name="contentType">text/html</param>
<param name="inputName">inputStream</param>
</result>
</action>
And my form looks like:
<s:head />
<sj:head />
<!-- This files are needed for AJAX Validation of XHTML Forms -->
<script src="${pageContext.request.contextPath}/struts/xhtml/validation.js" type="text/javascript"></script>
<s:form id="form" action="private/updateMySettings" theme="xhtml">
<s:textfield id="screenRes" key="appSetting.screenResolution" label="Screen resolution" required="true" />
<s:select key="appSetting.screenDepth" label="Color depth" list="#{'8':'8','16':'16','24':'24'}" required="true" />
<sj:submit value="Update Settings" targets="status" validate="true"/>
</s:form>
Unfortunately i get a javascript error if validation fails or not:
Uncaught TypeError: Object #<Object> has no method 'indexOf'
f.extend.ajax jquery-1.7.1.min.js:4
b.fn.ajaxSubmit
a.struts2_jquery.validateForm jquery.struts2-3.3.0.min.js:18
a.subscribeHandler.h.beforeSubmit jquery.struts2-3.3.0.min.js:18
b.fn.ajaxSubmit
a.subscribeHandler.e jquery.struts2-3.3.0.min.js:18
e.extend.each jquery-1.7.1.min.js:2
a.subscribeHandler.e jquery.struts2-3.3.0.min.js:18
f.event.dispatch jquery-1.7.1.min.js:3
f.event.add.h.handle.i jquery-1.7.1.min.js:3
f.event.trigger jquery-1.7.1.min.js:3
f.fn.extend.trigger jquery-1.7.1.min.js:3
e.extend.each jquery-1.7.1.min.js:2
e.fn.e.each jquery-1.7.1.min.js:2
f.fn.extend.trigger jquery-1.7.1.min.js:3
d.fn.extend.publish jquery.subscribe.min.js:16
e.extend.each jquery-1.7.1.min.js:2
d.fn.extend.publish jquery.subscribe.min.js:16
(anonymous function) jquery.struts2-3.3.0.min.js:18
f.event.dispatch jquery-1.7.1.min.js:3
f.event.add.h.handle.i jquery-1.7.1.min.js:3
It seems that the json object from the response can't be handled and i don't know why cause i followed the old instructions. I assume the cause is the function StrutsUtils.getValidationErrors from struts/utils.js if this function is used with the json object but i'm not sure. Can anyone help ?

I guess stream result and ajax doesn't play well together. just remove the targets
attribute. – jogep
I don't agree with you because the tenor of AJAX isn't load a new page but rather load pieces of whatever to the current page that is why i use an AJAX submit button. To notice the user of the action without reloading the page itself. The workaround is to clear the content of the status div element with javascript. I think that can be automated in struts2-jquery-plugin. This is my form which is embedded in tabbed pane.
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# taglib prefix="s" uri="/struts-tags" %>
<%# taglib prefix="sj" uri="/struts-jquery-tags"%>
<s:if test="appSetting != null">
<h3>Application settings</h3>
<div id="status" class="welcome"></div>
<table>
<tr>
<td>
<s:form id="form" action="updateMySettings" theme="xhtml">
<s:textfield id="screenRes" key="appSetting.screenResolution"
label="Screen resolution" required="true" />
<s:select key="appSetting.screenDepth" label="Color depth"
list="#{'8':'8','16':'16','24':'24'}" required="true" />
<sj:submit id="updateSetting" value="Update Settings" targets="status" validate="true" />
</s:form>
</td>
<td valign="top">
<button id="fullScreen">Use full screen</button>
<button id="fullBrowser">Use full browser</button>
</td>
</tr>
</table>
<script>
$("#fullScreen").click(function() {
scr_width = Math.max(screen.width,screen.height);
scr_height = Math.min(screen.width,screen.height);
$("#screenRes").val(scr_width + 'x' + scr_height);
});
$("#fullBrowser").click(function() {
brw_width = Math.max(window.innerWidth, window.innerHeight);
brw_height = Math.min(window.innerWidth, window.innerHeight);
$("#screenRes").val(brw_width + 'x' + brw_height);
});
$("#updateSetting").click(function() {
$("#status").empty();
})
</script>
</s:if>
<s:else>
<p>No settings available.</p>
</s:else>
It works very well.

You are step in an solved Struts2 Issue. Upgrade to latest version 2.3.3 or 2.3.4 and your problem should be gone.

Related

Botdetect Captcha HTML <taglib>

I want to add Botdetect Captcha to my html file.But in the website of the Botdetect captcha, there is example only for jsp. In this jsp file, <taglib> is used like that:
<%#taglib prefix="botDetect" uri="https://captcha.com/java/jsp"%>
....
<botDetect:captcha id="basicExample" userInputID="captchaCode" />
<div class="validationDiv">
<input name="captchaCode" type="text" id="captchaCode" value="${basicExample.captchaCode}" />
<input type="submit" name="validateCaptchaButton" value="Validate" id="validateCaptchaButton" />
<span class="correct">${basicExample.captchaCorrect}</span>
<span class="incorrect">${basicExample.captchaIncorrect}</span>
</div>
Is there any alternative for <%#taglib> in HTML files. How can I solve this problem?
I'm facing this problem because I use Thymeleaf instead of JSP so I can't use the taglib but I still have "dynamic HTML". I'm answering assuming this is your case.
I saw a possible solution on the help pages here: https://captcha.com/doc/java/jsp-captcha.html at section 2:
<%
// Adding BotDetect Captcha to the page
Captcha captcha = Captcha.load(request, "exampleCaptcha");
captcha.setUserInputID("captchaCode");
String captchaHtml = captcha.getHtml();
out.write(captchaHtml);
%>
This is JSP code but can be easily adapted to Thymeleaf. This in the #Controller that opens the page:
Captcha captcha = Captcha.load(request, "exampleCaptcha");
captcha.setUserInputID("captchaCode");
String captchaHtml = captcha.getHtml();
model.addAttribute("captchaHtml", captchaHtml);
and the html is like
<th:block th:utext="${captchaHtml}"></th:block>
The code for captcha checking is the same as for JSP, but placed in the #Controller that handles the form:
// validate the Captcha to check we're not dealing with a bot
boolean isHuman = captcha.validate(request.getParameter("captchaCode"));
if (isHuman) {
// TODO: Captcha validation passed, perform protected action
} else {
// TODO: Captcha validation failed, show error message
}
To finish you also need to edit web.xml (if you have it) and import the java libs as by the official docs. I'm using Gradle and importing 'com.captcha:botdetect-servlet:4.0.beta3.7'
Warning: your server should be on HTTPS or you might get this error when using version 4.0.beta3.7:
Captcha.UserInputID is not set. Your implementation of BotDetect is
not completely secure yet
<%#taglib prefix="botDetect" uri="https://captcha.com/java/jsp"%>
....
<botDetect:captcha id="basicExample" userInputID="captchaCode" />
<div class="validationDiv">
<input name="captchaCode" type="text" id="captchaCode" value="${basicExample.captchaCode}" />
<input type="submit" name="validateCaptchaButton" value="Validate" id="validateCaptchaButton" />
<span class="correct">${basicExample.captchaCorrect}</span>
<span class="incorrect">${basicExample.captchaIncorrect}</span>
</div>
That is wrong, with HTML (HyperText Markup Language) you have to list the version of HTML in this case it is Doctype HTML so the following one should be correct...
<!DOCTYPE html>
<%#taglib prefix="botDetect" uri="https://captcha.com/java/jsp"%>
....
<botDetect:captcha id="basicExample" userInputID="captchaCode" />
<div class="validationDiv">
<input name="captchaCode" type="text" id="captchaCode" value="${basicExample.captchaCode}" />
<input type="submit" name="validateCaptchaButton" value="Validate" id="validateCaptchaButton" />
<span class="correct">${basicExample.captchaCorrect}</span>
<span class="incorrect">${basicExample.captchaIncorrect}</span>
</div>

how to use dsp tags with jsonlib

i want to output some data within jsp using json format. i am trying to use json-taglib for same. Can someone please help me with combining jsontaglib with atg dsp tags? below is the code.
<%# taglib prefix="json" uri="http://www.atg.com/taglibs/json" %>
<dsp:page>
<json:property name="image" value="<dsp:valueof param='mysite.image'/>" />
<json:property name="name" value='<dsp:valueof param="mysite.name"/>' />
</json:object>`
</dsp:page>
But the code above is just printing my dsp:valueof tags instead of it's value. Why?
Also, i need to use foreach droplet to print out a nested json array.Can someone help me with an example on how can i achieve that?
TIA
Since you are explicitly importing the json taglib, you might need to import the dsp taglib too?
Apart from that you are missing a starting tag for your <json:object>, the rest appears to be correct.
An example of using the ForEach droplet to generate a nested json array is as follow:
<dsp:importbean bean="/atg/dynamo/droplet/ForEach" />
<dsp:page>
<json:object>
<json:property name="image">
<dsp:valueof param="mysite.image" />
</json:property>
<json:property name="name">
<dsp:valueof param="mysite.name" />
</json:property>
<json:array>
<dsp:droplet name="/atg/dynamo/droplet/ForEach">
<dsp:param name="array" param="SomeParameterPassedToThisDroplet" />
<dsp:oparam name="output">
<json:object>
<json:property name="element.propertyname">
<dsp:valueof param="element.propertyvalue" />
</json:property>
</json:object>
</dsp:oparam>
</dsp:droplet>
</json:array>
</json:object>
</dsp:page>

How to fix the Angular syntax parser error within a Struts 2 <s:checkbox> tag?

I have encountered a strange error using AngularJS + Struts 2.
I have a Java object form with a boolean attribute named paid.
When I write:
<div class="col-sm-10 form-checkbox">
<s:checkbox name="xxxxx" ng-model="model"
ng-init="model = <s:property value = '%{form.paid}' />"
theme="simple" />
</div>
I get FireBug complaining about AngularJS syntax parser error which directs me to this page:
syntax error page
suggesting expression error.
And if I write:
<div class="col-sm-10 form-checkbox">
<s:checkbox name="xxxxx" ng-model="model"
ng-init="%{form.paid}"
theme="simple" />
</div>
No error is reported. I guess it is because Struts tags begin with <, which is not welcomed in Angular.
But, with this line no error is reported:
<select ng-model="estadoId"
ng-init="estadoId=<s:property value='%{form.estadoId}'/>"
name="form.estadoId" id="form.estadoId"
value="<s:property value='%{form.estadoId}' />" >
So, AngularJS is complaining about <> in Struts 2? Or, I am nor permitted to use <s:...> inside another <s:...>? If the latter is the case, why is complaning Angular not Struts 2??
In the first snippet, you are nesting Struts tags, that is a syntax error:
<s:checkbox name="xxxxx"
ng-model="model"
ng-init="model = <s:property value = '%{form.paid}' />"
theme="simple" />
In the second one, you are doing it right with OGNL, but you omitted the model = part:
<s:checkbox name="xxxxx"
ng-model="model"
ng-init="%{form.paid}"
theme="simple" />
The right version is the mix of the two:
<s:checkbox name="xxxxx"
ng-model="model"
ng-init="model = %{form.paid}"
theme="simple" />
Otherwise you could use a raw HTML tag (as in your <select> example, that is a standard HTML tag and not an <s:select>, hence no tags nesting is happening):
<input type="check" name="xxxxx"
ng-model="model"
ng-init="model = %{form.paid}" />
Note: in that case, you should create an hidden parameter under each checkbox to emulate the <s:checkbox> tag behavior and make the Checkbox Interceptor happy.

load parts of a JSON in many divs + Struts2

I need load the content of a Object JSON in many divs, but in parts. For example,
My JSON structure:
{"Example": {
"Hi": "hi",
"Bye": "bye"
}
}
Assuming that the JSON string successfully load my JSP page. I am trying to load the contents of the JSON like this:
(For the attribute Hi and Bye)
<sj:div id="div1" dataType = "json">
<s:property value="Example.Hi"/>
</sj:div>
<sj:div id="div2" dataType = "json">
<s:property value="Example.Bye"/>
</sj:div>
Struts.xml:
<action name="name" class="class" method="method">
<result type="json">
<param name="root">
Example
</param>
</result>
</action>
but this doesn't work... What I can do?
I'm using: Struts2 Jquery Library
You should build the URL like
<s:url var="remoteurl1" action="name"><s:param name="div1" value="true"/></s:url>
<sj:div id="div1" href="%{#remoteurl1}" dataType = "json"/>
<s:url var="remoteurl2" action="name"><s:param name="div2" value="true"/></s:url>
<sj:div id="div2" href="%{#remoteurl2}" dataType = "json"/>
Then in your action you check if isDiv1() or isDiv2() and return corresponding result.

Dynamically Creating list in Struts2 using tags

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(2012);
list.add(2013);
list.add(2014);
list.add(2015);
can we do same as above using struts2 tags. may be by using
<s:set name="myList" value={somedynamic values} />
actually I want to create a list of number of 10 years on JSP page using Struts2 tags.
Regarding to your question answer is yes,but that is not an good idea to create number of 10 years in jsp page.
However, this is using arrylist in dynamic way
     
<s:select label="Years" headerKey="-1" headerValue="Select Years" list="list" name="your desire name" />
in the place of list property you have to give arrayList variable in your case it is list
means,
<s:select ---- list="your array list variable" --------- />
     and you have to define this action name in struts.xml
   eg:
<action name="yourarrylistvariable" class="your class" method="your method">
<result name="success">your jsp page</result>
</action>
    
     This is using arrylist in static way here you have to change the list value 
<s:select label="Years" headerKey="-1" headerValue="Select Years"
list="#{'2000':'2000', '2013':'2013',.....}" name="your desire name" />
For More Info You can refer this link struts2 select
Sure you can, thanks to the OGNL you can create lists like so:
<s:set var="myList" value="{2012,2013,2014,2015}" />
See this link.