validation using ajax in struts2 - ajax

I used ajax validation to validate the following
<tr>
<td width="20" style='color: red'>
<img src="images/icon-star.png" width="16" height="16" />
</td>
<td id="lblCustomBillNo" style="width: 15%" class="searchCriteriaCellLbl">
The custom Bill Number
</td>
<td width="5" class="searchCriteriaCellLbl">:</td>
<td class="searchCriteriaCellVal">
<s:textfield id="customBillNo" name="customBillNo" size="20" maxlength="24" style="width: 200px" />
</td>
<td class="errorFlag" style="color: red" valign="middle">
<s:fielderror fieldName="customBillNo" />
</td>
</tr>
<tr>
<td width="20" style='color: red'>
<img src="images/icon-star.png" width="16" height="16" />
</td>
<td id="lblBillNo" style="width: 15%" class="searchCriteriaCellLbl">
<s:property value="%{getText('billNo')}" />
</td>
<td width="5" class="searchCriteriaCellLbl">:
</td>
<td class="searchCriteriaCellVal">
<s:textfield label="billNo" id="billNo" name="billNo" size="20" maxlength="24" style="width: 200px" />
</td>
<td class="errorFlag" style="color: red" valign="middle">
<s:fielderror fieldName="billNo" />
</td>
</tr>
<tr>
<td width="20" style='color: red'>
<img src="images/icon-star.png" width="16" height="16" />
</td>
<td id="lblCarrierNo" style="width: 15%" class="searchCriteriaCellLbl">
The carrier Number
</td>
<td width="5" class="searchCriteriaCellLbl">:
</td>
<td class="searchCriteriaCellVal">
<s:textfield label="carrierNo" id="carrierNo" name="carrierNo" size="20" maxlength="24" style="width: 200px" />
</td>
<td class="errorFlag" style="color: red" valign="middle">
<s:fielderror fieldName="carrierNo" />
</td>
</tr>
I use the following internationalization for errors in golbal i18n file
errors.required=${getText(fieldName)} requireddd
and this validation file
<validators>
<field name="customBillNo">
<field-validator type="requiredstring" short-circuit="true">
<param name="trim">true</param>
<message key="errors.required" />
</field-validator>
</field>
<field name="billNo">
<field-validator type="required" short-circuit="true">
<message key="errors.required" />
</field-validator>
</field>
<field name="carrierNo">
<field-validator type="required" short-circuit="true">
<message key="errors.required" />
</field-validator>
</field>
</validators>
and i put this javascript to use ajax validation
function validate(){
//document.all.loading.style.display = 'block';
var searchUrl = 'AddEnteringApproval_approval';
var params = '';
var elemArray = document.mainForm.elements;
for (var i = 0; i < elemArray.length;i++)
{
var element = elemArray[i];
var elementName= element.name;
if(elementName=='formAction')
continue;
params += '&' + elementName+'='+ encodeURIComponent(element.value);
}
params += '&struts.enableJSONValidation=true&struts.validateOnly=true';
createXmlHttpObject(); // this is my function that prepare ajax
sendRequestPost(http_request,searchUrl,false,params);
postValidation();
}
function postValidation() {
var form = $('#mainForm');
var text = http_request.responseText;
//clear previous validation errors, if any
StrutsUtils.clearValidationErrors(form);
alert(text)
//get errors from response
//var text = request.responseText;
var errorsObject = StrutsUtils.getValidationErrors(text);
//show errors, if any
if(errorsObject.fieldErrors)
{
StrutsUtils.showValidationErrors(form, errorsObject);
}
else
{
//good to go, regular submit
form.submit();
}
}
/* This is one of the functions that doesn't work using the simple theme, so I redefined it.
This can be changed to clear the previous errors, as it does in the commented example
cleaning the errors on divErrors.
As I am just showing the messages with alerts I don't need to clear anything,
but the method still need to be redefined, even if it is empty.
*/
StrutsUtils.clearValidationErrors = function(form, errors) {
//clear the div errors
//$('#divErrors').empty();
}
/* This method is responsible to show the messages.
The original versions works with the xhrml and css-xhtml theme but doesn't work with the simple theme
so I override the method with another implementation that shows the messages using alerts.
You can change the implementation to show the messages as you want,
but as the previous method this has to be redefined.
*/
StrutsUtils.showValidationErrors = function(form, errors) {
if(errors.fieldErrors)
{alert((errors.fieldErrors))
for(var fieldName in errors.fieldErrors)
{
alert("errors.fieldErrors[fieldName] " + errors.fieldErrors[fieldName]);
for(var i = 0; i < errors.fieldErrors[fieldName].length; i++)
{
alert('Field ->' + fieldName + '\nError -> ' + errors.fieldErrors[fieldName][i]);
}
}
}
};
but when i execute the code i get no organized JSON text i showed in alert message box, the field name is not like the one in the error message, the second field name is missing, the third field name is cut (i.e. carrierNo becomes rNo ).
can you help me. i want the field name in the JSON error match the error message text
I just figured out what is the problem, but i don't know why it happens and why.
it always remove the first 6 characters. why this happens

well I figured out the problem.
it was a but in org.apache.struts2.interceptor.validation.JSONValidationInterceptor
it removes the 6 first characters because of this incomplete if statement
sb.append((validationAware instanceof ModelDriven) ? ((String)fieldError.getKey()).substring(6) : (String)fieldError.getKey());
this error is fuond in struts 2.1.8
it should be like this
sb.append(((validationAware instanceof ModelDriven)) && (fieldErrorKey.startsWith("model.")) ? fieldErrorKey.substring(6) : fieldErrorKey);
it was corrected in later struts releses. i corrected the problem. and i thought i have to share the information for people who faces the problem.

Related

Custom sort for String with 3 set of values in datatables

I have used datables on one of my html tables. There are multiple columns currenltly in it.
One of the columns in it can contain one of the below three values:
Amber
Pending
Red
I want to implement sorting such that all rows with value Pending are seen first, then Amber and then Red. (Cannot use the default ascending and descending sorting as the order will not be correct then)
code Snippet:
JSP (Table creation)
<table class="tableContent nofx cell-border compact" id="violationTable">
<thead>
<tr>
<th class="col1"><i18n:message key="rule.name" /></th>
<th class="col2"><i18n:message key="rule.value" /></th>
<th class="col3"><i18n:message key="rule.isr.value" /></th>
<th class="col4"><i18n:message key="rule.status" /></th>
</tr>
</thead>
<tbody>
<c:forEach items="${ruleViolationList}" var="i" varStatus="loopStatus">
<tr data-rule-id="<c:out value="${i.id}" />" data-country-id="<c:out value="${i.countryId}" />"
>
<td class="col1">
<c:out value="${i.PolicyRule}" />
</td>
<td class="col2">
<c:out value="${i.RuleValue}" escapeXml="false" />
</td>
<td class="col3">
<c:out value="${i.isrValue}" />
</td>
<c:choose>
<c:when test="${i.violationTypeId == 1}">
<td class="red status" >
<i18n:message key="rule.violation.red" />
</td>
</c:when>
<c:when test="${i.violationTypeId == 2}">
<td class="amber status" >
<i18n:message key="rule.violation.amber" />
</td>
</c:when>
<c:when test="${i.violationTypeId == 4}">
<td class="blue status" >
<i18n:message key="rule.violation.dispensation.approval.pending" />
</td>
</c:when>
<c:when test="${i.violationTypeId == 5}">
<td class="amber status" >
<i18n:message key="rule.violation.amber" />
</td>
</c:when>
<c:when test="${i.violationTypeId == 6}">
<td class="red status" >
<i18n:message key="rule.violation.red" />
</td>
</c:when>
</c:choose>
</tr>
</c:forEach>
</tbody>
</table>
Servlet:
ArrayList<RuleViolation> ruleViolationList = daoFactory.getRuleViolationsDAO().list();
request.setAttribute("ruleViolationList", ruleViolationList);
JS:
$(document).ready(function() {
$('#violationTable').DataTable();
});
So what i ideally want is, when the table is shown on page the data should be sorted alphabetically based on data in first column as well as data in last column (i.e Pending, Amber and then Red).
Check out the snippet, you can highly customize how your column is filtered/sorted using the option columns.render.
The example I gave is not the smartest, but gives you one idea of what you can make. I advice you to use "Nested Object data" if you choose this approach.
var dataSet = [
['Name1', 3, 'Red'],
['Name2', 2, 'Amber'],
['Name3', 1, 'Pending']
];
$(document).ready(function() {
$('#example').DataTable( {
data: dataSet,
columns: [
{ title: "Name" },
{ title: "Value" },
{
title: "Types",
"render": function ( data, type, full, meta ) {
if (type == 'sort') {
if (data == 'Red') return 3;
else if(data == 'Pending') return 1;
else if(data == 'Amber') return 2;
} else {
return data;
}
}
}
]
} );
} );
<link href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" rel="stylesheet"/>
<script src="//code.jquery.com/jquery-1.12.3.js"></script>
<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
<table id="example" class="display" width="100%"></table>

Knockout-Validation - data-bind observable array

I'm trying to do some validation for groups of radio buttons, where each group needs to have a value selected. I'm attempting to use Knockout-Validation to do the validation, but I'm having trouble making this dynamic. I can set up the validation, but getting it to validate each group individually is a challenge. Right now it's treating all groups of questions the same. I have an example on JSFiddle which shows the current situation.
I create the questions dynamically in the back end from a DB, but I could potentially add in a unique identifier for each question, but how do I reference an observable who's name I can't know ahead of time for a number of questions I can't predetermine the number of?
Example code form JSFiddle:
$(function() {
var viewModelQuestionnaire = ko.validatedObservable({
'checkScore': ko.observable().extend({
required: true
}),
submit: function () {
if (this.isValid()) {
alert('Thank you.');
} else {
console.log(this);
alert('Please check your submission.');
this.errors.showAllMessages();
}
}
});
ko.applyBindings(viewModelQuestionnaire);
});
<form action="/Questionnaire/Save" method="post"> <table id="ESAS-questions">
<tr class="esas-question-row">
<td class="esas-best-area">
<div class="esas-best-symptom">No Pain</div>
</td>
<td class="esas-score-area">
<span class="esas-score">0<input type="radio" name="question_id-1" value="0" data-bind="checked: checkScore"/></span>
<span class="esas-score">1<input type="radio" name="question_id-1" value="1" data-bind="checked: checkScore"/></span>
<span class="esas-score">2<input type="radio" name="question_id-1" value="2" data-bind="checked: checkScore"/></span></td>
<td class="esas-worst-area">
<span class="esas-worst-symptom">Worst Possible Pain</span>
</td>
</tr>
<tr class="esas-question-row">
<td class="esas-best-area">
<div class="esas-best-symptom">No Tiredness</div>
<div class="esas-best-subtext">(Tiredness = lack of energy)</div>
</td>
<td class="esas-score-area">
<span class="esas-score">0<input type="radio" name="question_id-2" value="0" data-bind="checked: checkScore"/></span>
<span class="esas-score">1<input type="radio" name="question_id-2" value="1" data-bind="checked: checkScore"/></span>
<span class="esas-score">2<input type="radio" name="question_id-2" value="2" data-bind="checked: checkScore"/></span> </td>
<td class="esas-worst-area">
<span class="esas-worst-symptom">Worst Possible Tiredness</span>
</td>
</tr>
</table>
<p><input type="submit" value="Submit" class="finish" data-bind="click:submit" /></p>
You can avoid multiple error message for that you have to customize the display of your objects validation message by using validationMessage binding and stop the default error message insertion with knockout validation options.
data-bind="validationOptions: { insertMessages: false }" //default validation will not insert
// customize the display of your objects validation message
<p class="invalid" data-bind="validationMessage: checkScore"></p>
You have binded same property to both question so whenever one field is selected it select other one also.You can have list of questions as array of objects in observableArray.
Sample structure for list of questions:-
var questions=[
{
question: "No Pain",
checkScore: ko.observable().extend({
required: true
}),
description: "Worst Possible Pain"
},
{
question: "No Tiredness (Tiredness = lack of energy)",
checkScore: ko.observable().extend({
required: true
}),
description: "Worst Possible Tiredness"
}
]
But for questionList validation you have to enable deep(recursive) validation.
Fiddle Demo

Encounter error when there is if else in mvc view

i am new in mvc and trying to learn.i want to display a form when ViewBag.Success is null or empty but if ViewBag.Success is true then i want to render a partial view.
here is my code
<div id="mydiv">
#if (ViewBag.Success != null && ViewBag.Success == true) //Show the message
{
Html.RenderPartial("Message");
}
else
{
#using (Html.BeginForm("Save", "Game", FormMethod.Post, new { #Id = "Form1" }))
{
<table border="0">
<tr>
<td>
Name :
</td>
<td>
<input name="name" type="text" />
</td>
</tr>
<tr>
<td>
Salary :
</td>
<td>
<input name="salary" type="text" />
</td>
</tr>
<tr>
<td colspan="2">
<input name="btnSubmit" type="submit" value="Save" />
</td>
</tr>
</table>
}
}
</div>
the error message i am getting when i am running like
Expected a "{" but found a "/". Block statements must be enclosed in "{" and "}". You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
what i am doing wrong not being able to understand. please help & guide. thanks
# symbol is only required when your code is contained within an HTML element. The using statement does not need the # because it is a direct decedent of your if else block.
Example:
<div> <!-- html tag -->
#if(something == somethingElse) // requires # because direct decedent of html tag <div>
{
<p>
#for (var i=0; i < len; i++) // requires # because direct decedent of html tag <p>
{
if(i == 1) // doesnt require #, not decedent of any HTML tag, instead direct decedent of another razor statement (for)
{
//do something
}
}
</p>
}
</div>
The # sign is use to distinguish between a simple string / HTML and razor statements. You only need that when you are writing C# code between HTML code. But when you are have started a C# code block, the ASP.NET MVC View Engine is intelligent enough to understand that the code that follows is C# and not simply some string.

How to retrieve multiple records from Jquery to my RazorView page

I have a button "btnGetAddress" on my razor page .On clik of this button,I am calling a Jquery to get my addressItmes object to be displayed on to my View page.
On clicking "btnGetAddress" I am able to hit my "JsonResult GetAddresses()" and retrieve records within my Jquery (success: function (data)).and this data has multiple address records. But I do not know how to take this data to my view .Please help me to get my data to be displayed on to my View
When my page get loaded,the user will see only the "btnGetAddress" button .When the user click on the btnGetAddress, it will call the Jquery Click function to fetch all address records from database and display each set of records on the page
$("#btnGetAddress").click(function () {
debugger;
var selected = $("#ddlType").val();
if (selected == "")
{ selected = 0; }
var dataToSend = {
SelectedTypeId: selected
};
$.ajax({
type: "GET",
url: '#Url.Action("GetAddresses", "Content")',
data: { SelectedTypeId: selected },
success: function (data) {
debugger;
},
error: function (error) {
var verr = error;
alert(verr);
}
});
pasted below is my JsonResult GetAddresses() which gets called to retrieve addressItems
public JsonResult GetAddresses()
{
model.AddressItems = AddressService.RetrieveAllAddress();
// My AddressItems is of type IEnumerable<AddressItems>
return Json(model.AddressItems, JsonRequestBehavior.AllowGet);
}
Here is my razor View Page where the address records are to be displayed.
........................
<input type="submit" id="btnGetAddress" name="btnSubmit" value="Show Addresses" />
if (!UtilityHelper.IsNullOrEmpty(Model.AddressItems))
{
foreach (var AddressRecord in Model.AddressItems)
{
<fieldset >
<legend style="padding-top: 10px; font-size: small;">Address Queue(#Model.NumRecords)
</legend>
<table>
<tr>
<td>
<span>Index</span>
</td>
<td>
</td>
<td>
<input type="submit" id="btnDelete" name="btnSubmit" value="X" />
<br />
</td>
</tr>
<tr>
<td>
<span>Address1</span>
<br />
</td>
<td>
#Html.EditorFor(model => AddressRecord.Address )
#Html.ValidationMessageFor(model => AddressRecord.Address)
</td>
</tr>
<tr>
<td>
<span>Description</span>
<br />
</td>
<td>
#Html.EditorFor(model => AddressRecord.Description)
#Html.ValidationMessageFor(model => AddressRecord.Description)
</td>
</tr>
<tr>
<td>
<input type="submit" id="btnSave" name="btnSubmit" value="Save" />
</td>
<td>
<input type="submit" id="btnDelete" name="btnSubmit" value="Delete" />
</td>
</tr>
</table>
</fieldset>
}
}
<fieldset>
Or is there any better way to achieve my objective?
Since you are getting the data via ajax you should use a jquery template engine. Basically get the data the way you are and on success you do something like
<script language="javascript" type="text/javascript">
$(function () {
$.getJSON("/getprojects", "", function (data) {
$("#projectsTemplate").tmpl(data).appendTo("#projectsList");
});
});
</script>
<script id="projectsTemplate" type="text/html">
<section>
<header><h2>Projects</h2></header>
<table id="projects">
<th>Name</th>
{{tmpl(items) "#projectRowTemplate"}}
</table>
</section>
</script>
<script id="projectRowTemplate" type="x-jquery-tmpl">
<tr>
<td>${name}</td>
</tr>
</script>
<div id="projectsList"></div>
Now each template engine is different but the above gives you an idea of what you can do
If you want to return JSON object in your controller, you are going have to turn your view into a string and return it as part of the message. If you google there are some methods out there that can do this.
However, I really think that's the hard way, why not take the data you get from the JSON in the controller and put it in a MODEL and then return your VIEW with the model data passed in. I think that's the easier way.

Why do I get IllegalArgumentException Cannot convert value of type String to required type Product, in Spring?

I receive the exception
Failed to convert property value of
type [java.lang.String] to required
type [beans.Product] for property
product; nested exception is
java.lang.IllegalArgumentException:
Cannot convert value of type
[java.lang.String] to required type
[beans.Product] for property product:
no matching editors or conversion
strategy found
in the Errors errors object even before my DetailProductValidator starts validating through the validate method.
I don't understand why Spring does that. I don't have any input field that is mapped directly to the product property/object. I just use the product object's properties in the jsp. For example, I use:
<form:options items="${dpBackObj.product.colorMap}"/>
<!-- or -->
${dpBackObj.product.priceInDollars}
but I never use:
<form:input path="product"/>
Can anyone please explain why this happens? And maybe inform me of a simple solution?
The bean configuration for the controller is:
<!-- DETAIL PRODUCT FORM CONTROLLER -->
<bean id="productDetailFormController" name="/detail.htm /addToCart.htm"
class="detailProduct.DetailProductFormController">
<property name="sessionForm" value="true" />
<property name="commandName" value="dpBackObj" />
<property name="commandClass" value="detailProduct.DetailProductBackingObject" />
<property name="validator">
<bean class="detailProduct.DetailProductValidator" />
</property>
<property name="formView" value="detail" />
<property name="successView" value="redirect:/viewCart.htm" />
<property name="cartService" ref="cartServiceImpl"/>
</bean>
The backing object for the DetailProductFormController is:
public class DetailProductBackingObject {
private String quantityOverflowError;
private Product product;
private int quantity;
private ShoppingCart shoppingCart;
private long sizeId;
private long colorId;
public DetailProductBackingObject() {
this.product = new Product();
this.sizeId = -1;
this.colorId = -1;
}
//getters and setters
}
If you need some other info, I will provide. I am using Spring 2.5.5.
Kind Regards,
Despot
EDIT1 (due to request from axtavt):
<form:form method="post" commandName="dpBackObj">
<table width="730" border="0" cellspacing="0" cellpadding="0">
<c:if test="${!empty dpBackObj.quantityOverflowError}">
<tr>
<td>
<c:out value="${dpBackObj.quantityOverflowError}"/>
</td>
</tr>
</c:if>
<spring:bind path="dpBackObj.*">
<c:if test="${not empty status.errorMessages}">
<div class="val-summary text-error" id="errorDivId">
<div style="" class="val-summary text-error" id="errorDivId">
<fmt:message key="detail.error.header"/>
<ul>
<c:forEach items="${status.errorMessages}" var="error">
<li><c:out value="${error}"/></li>
</c:forEach>
</ul>
</div>
</div>
</c:if>
</spring:bind>
<tr>
<td width="310" align="left" valign="top">
<img src="${imagesPath}/${dpBackObj.product.largeImageUrl}" alt="${dpBackObj.product.description}" />
</td>
<td width="420" align="left" valign="top">
<div id="tls_detPName">
<c:out value="${dpBackObj.product.name}"></c:out>
</div>
<div >
<strong class="numeric">${dpBackObj.product.priceInDollars}</strong>
</div>
<div id="tls_detPDescLong">
${dpBackObj.product.largeDescription}
<br />
</div>
<div >
<table cellpadding="2" border="0">
<tr>
<td align="right">
<label for="p_sizes" class="label"><fmt:message key="viewCart.Size"/></label>
</td>
<td>
<form:select path="sizeId" >
<form:option value="-1" label="x"/>
<form:options items="${dpBackObj.product.sizeMap}"/>
</form:select>
</td>
</tr>
<tr>
<td align="right">
<label for="p_colors" class="label"><fmt:message key="viewCart.Color"/></label>
</td>
<td>
<form:select path="colorId" >
<form:option value="-1" label="y"/>
<form:options items="${dpBackObj.product.colorMap}"/>
</form:select>
</td>
</tr>
</table>
</div>
<div id="tls_addToCart">
<div >
<label for="quantityId" class="label"><fmt:message key="viewCart.Quantity"/>:</label>
<form:input path="quantity" onkeypress="return checkForNumber(this, event)" maxlength="10" size="3" id="quantityId" cssClass="textbox-center"/>
<input type="image" name="addToCartButtonName" src="${imagesPath}/addToCartBtn.jpg" />
</div>
</div>
</td>
</tr>
</table>
</form:form>
EDIT2 (due to JacobM's request):
This is my Validator:
public class DetailProductValidator implements Validator {
public boolean supports(Class clazz) {
return DetailProductBackingObject.class.equals(clazz);
}
public void validate(Object obj, Errors errors) {
DetailProductBackingObject detailProductBackingObject = (DetailProductBackingObject) obj;
if (detailProductBackingObject.getSizeId() == -1) {
errors.rejectValue("sizeId", "error.detail.jsp.choose.size", null, "Input size.");
}
}
}
When I reach the line DetailProductBackingObject detailProductBackingObject = I already have the error.
The converting of the request parameters to the backing object properties happens in http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html . This is what Spring says about the conversion:
Populating using request parameters
and PropertyEditors: Upon receiving a
request, any BaseCommandController
will attempt to fill the command
object using the request parameters.
This is done using the typical and
well-known JavaBeans property
notation. When a request parameter
named 'firstName' exists, the
framework will attempt to call
setFirstName([value]) passing the
value of the parameter. Nested
properties are of course supported.
For instance a parameter named
'address.city' will result in a
getAddress().setCity([value]) call on
the command class.
It's important to realise that you are
not limited to String arguments in
your JavaBeans. Using the
PropertyEditor-notion as supplied by
the java.beans package, you will be
able to transform Strings to Objects
and the other way around. For instance
setLocale(Locale loc) is perfectly
possible for a request parameter named
locale having a value of en, as long
as you register the appropriate
PropertyEditor in the Controller (see
initBinder() for more information on
that matter.
Validators: After the controller has
successfully populated the command
object with parameters from the
request, it will use any configured
validators to validate the object.
Validation results will be put in a
Errors object which can be used in a
View to render any input problems.
Since I can't see anything wrong with the form, the only possible reason I can imagine is that you have a parameter named product in the URL of your form page.
If so, you can change your URLs or use DataBinder.setDisallowedFields() to disable the attempt to bind that parameter.

Resources