http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/ajax-validation.html ---------------------------------------------------------------------- diff --git a/content/docs/ajax-validation.html b/content/docs/ajax-validation.html new file mode 100644 index 0000000..e67d57d --- /dev/null +++ b/content/docs/ajax-validation.html @@ -0,0 +1,529 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>AJAX Validation</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="guides.html">Guides</a> > <a href="core-developers-guide.html">Core Developers Guide</a> > <a href="validation.html">Validation</a> > <a href="client-side-validation.html">Client Side Validation</a> > <a href="pure-javascript-client-side-validation.html">Pure JavaScript Client Side Validation</a> > <a href="ajax-client-side-validation.html">AJAX Client Side Validation</a> > <a href="ajax-validation.html">AJAX Validation</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">AJAX Validation</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13850"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13850">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13850"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13850">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13850"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13850">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"><p><style type="text/css">/*<![CDATA[*/ +div.rbtoc1488973446459 {padding: 0px;} +div.rbtoc1488973446459 ul {list-style: disc;margin-left: 0px;} +div.rbtoc1488973446459 li {margin-left: 0px;padding-left: 0px;} + +/*]]>*/</style></p><div class="toc-macro rbtoc1488973446459"> +<ul class="toc-indentation"><li><a shape="rect" href="#AJAXValidation-Description">Description</a></li><li><a shape="rect" href="#AJAXValidation-Example">Example</a> +<ul class="toc-indentation"><li><a shape="rect" href="#AJAXValidation-Createtheactionclass">Create the action class</a></li><li><a shape="rect" href="#AJAXValidation-MaptheAction">Map the Action</a></li><li><a shape="rect" href="#AJAXValidation-CreatetheJSP">Create the JSP</a></li><li><a shape="rect" href="#AJAXValidation-CustomTheme">Custom Theme</a></li><li><a shape="rect" href="#AJAXValidation-CSS">CSS</a></li><li><a shape="rect" href="#AJAXValidation-JavaScript">JavaScript</a></li></ul> +</li><li><a shape="rect" href="#AJAXValidation-Howitworks">How it works</a></li><li><a shape="rect" href="#AJAXValidation-JSONValidationInterceptorparameters">JSONValidationInterceptor parameters</a></li><li><a shape="rect" href="#AJAXValidation-FlowchartofAJAXvalidation">Flow chart of AJAX validation</a></li></ul> +</div><h2 id="AJAXValidation-Description">Description</h2><p>Struts provides <a shape="rect" href="client-validation.html">client side validation</a>(using JavaScript) for a few validators. Using AJAX validation, all <a shape="rect" href="validation.html">validators</a> available to the application on the server side can be used without forcing the page to reload, just to show validation errors. AJAX validation has a server side, which is in included in <a shape="rect" href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=34268">JSON Plugin</a> (an interceptor and a result). Client side must be handled by applictions themself. One reason for that is there are too many JavaScript frameworks and libraries. Struts has no preference which of them you use. Previous versions of Struts included a client side which was relying on the Dojo JS framework and was located in Struts Dojo plugin. That has been deprecated for a long time and was eventually removed.</p><h2 id="AJAXV alidation-Example">Example</h2><p>This example is taken from the Struts showcase application.</p><h3 id="AJAXValidation-Createtheactionclass">Create the action class</h3><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class AjaxFormSubmitAction extends ActionSupport { + private String requiredValidatorField = null; + private String requiredStringValidatorField = null; + private Integer integerValidatorField = null; + private Date dateValidatorField = null; + private String emailValidatorField = null; + private String urlValidatorField = null; + private String stringLengthValidatorField = null; + private String regexValidatorField = null; + private String fieldExpressionValidatorField = null; + @Override + public void validate() { + if (hasFieldErrors()) { + addActionError("Errors present!"); + } + } + public Date getDateValidatorField() { + return dateValidatorField; + } + @DateRangeFieldValidator( + min="01/01/1990", + max="01/01/2000", + message="must be a min 01-01-1990 max 01-01-2000 if supplied") + public void setDateValidatorField(Date dateValidatorField) { + this.dateValidatorField = dateValidatorField; + } + public String getEmailValidatorField() { + return emailValidatorField; + } + @EmailValidator(message="must be a valid email if supplied") + public void setEmailValidatorField(String emailValidatorField) { + this.emailValidatorField = emailValidatorField; + } + public Integer getIntegerValidatorField() { + return integerValidatorField; + } + @IntRangeFieldValidator(min="1", max="10", message="must be integer min 1 max 10 if supplied") + public void setIntegerValidatorField(Integer integerValidatorField) { + this.integerValidatorField = integerValidatorField; + } + public String getRegexValidatorField() { + return regexValidatorField; + } + @RegexFieldValidator( + regex="[^<>]+", + message="regexValidatorField must match a regexp (.*\\.txt) if specified") + public void setRegexValidatorField(String regexValidatorField) { + this.regexValidatorField = regexValidatorField; + } + public String getRequiredStringValidatorField() { + return requiredStringValidatorField; + } + @RequiredStringValidator(trim=true, message="required and must be string") + public void setRequiredStringValidatorField(String requiredStringValidatorField) { + this.requiredStringValidatorField = requiredStringValidatorField; + } + public String getRequiredValidatorField() { + return requiredValidatorField; + } + @RequiredFieldValidator(message="required") + public void setRequiredValidatorField(String requiredValidatorField) { + this.requiredValidatorField = requiredValidatorField; + } + public String getStringLengthValidatorField() { + return stringLengthValidatorField; + } + @StringLengthFieldValidator( + minLength="2", + maxLength="4", + trim=true, + message="must be a String of a specific greater than 1 less than 5 if specified") + public void setStringLengthValidatorField(String stringLengthValidatorField) { + this.stringLengthValidatorField = stringLengthValidatorField; + } + public String getFieldExpressionValidatorField() { + return fieldExpressionValidatorField; + } + @FieldExpressionValidator( + expression = "(fieldExpressionValidatorField == requiredValidatorField)", + message = "must be the same as the Required Validator Field if specified") + public void setFieldExpressionValidatorField( + String fieldExpressionValidatorField) { + this.fieldExpressionValidatorField = fieldExpressionValidatorField; + } + public String getUrlValidatorField() { + return urlValidatorField; + } + @UrlValidator(message="must be a valid url if supplied") + public void setUrlValidatorField(String urlValidatorField) { + this.urlValidatorField = urlValidatorField; + } +}</pre> +</div></div><p> </p><h3 id="AJAXValidation-MaptheAction">Map the Action</h3><p>Note that is is not necessary when using <a shape="rect" href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=73711">Convention Plugin</a>.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> + +<struts> + <package> + <action name="ajaxFormSubmit" class="org.apache.struts2.showcase.validation.AjaxFormSubmitAction"> + <interceptor-ref name="jsonValidationWorkflowStack"/> + <result name="input">/WEB-INF/validation/ajaxFormSubmit.jsp</result> + <result type="jsonActionRedirect">ajaxFormSubmitSuccess</result> + </action> + </package> +</pre> +</div></div><p>AJAX validation is performed by the <em>jsonValidation</em> interceptor. This interceptor is included in the <em>jsonValidationWorkflowStack</em>, and is required in order to perform AJAX validation. Normal results(input, success, etc) should be provided for the action in the case that someone tries to access the action directly, in which case normal validation will be triggered. So, how does the <em>jsonValidation</em> know that it must perform AJAX validation vs regular validation? We will see that in a minute, but you don't need to know that in order to use AJAX validation. Same applies for specialized Redirect Result Type <em>jsonActionRedirect</em>.</p><h3 id="AJAXValidation-CreatetheJSP">Create the JSP</h3><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: html; gutter: false; theme: Default" style="font-size:12px;"><%@taglib prefix="s" uri="/struts-tags" %> +<html> +<head> + <title>Struts2 Showcase - Validation - AJAX Form Submit</title> + <s:head theme="xhtml"/> +</head> +<body> +<div class="page-header"> + <h1>AJAX Form Submit</h1> +</div> + <h3>Action Errors Will Appear Here</h3> + <s:actionerror theme="ajaxErrorContainers"/> + <hr/> + <s:form method="POST" theme="xhtml"> + <s:textfield label="Required Validator Field" name="requiredValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="Required String Validator Field" name="requiredStringValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="Integer Validator Field" name="integerValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="Date Validator Field" name="dateValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="Email Validator Field" name="emailValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="URL Validator Field" name="urlValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="String Length Validator Field" name="stringLengthValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="Regex Validator Field" name="regexValidatorField" theme="ajaxErrorContainers"/> + <s:textfield label="Field Expression Validator Field" name="fieldExpressionValidatorField" theme="ajaxErrorContainers"/> + <s:submit label="Submit" cssClass="btn btn-primary"/> + </s:form> +</body> +</html> </pre> +</div></div><p>Things to note on this JSP:</p><ul><li>The <em>form</em> tag <strong>does not</strong> have <em>validate</em> set to <em>true</em>, which would perform client validation before the AJAX validation.</li><li>It uses a customized theme <em>ajaxErrorContainers</em>. The default Struts themes generate HTML-Elements to show validation errors only if errors are present when page is created on server side. But in order to show validation errors that arrive later via AJAX it is necessary to have error-container elements in DOM always.</li></ul><p>What happens if validation succeeds? That depends on your request parameters and action configuration. If you are using <em>jsonActionRedirect</em> result mentioned above the action will be executed while AJAX request is active and respond with JSON providing a new URL to load. Otherwise the AJAX response will be empty and the form must be submitted a 2nd time but as usual request, not AJAX.</p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Setting <em>validate</em> to <em>true</em> in the <em>form</em> tag will enable client side, JavaScript validation, which can be used along with AJAX validation (runs before the AJAX validation).</p></div></div><h3 id="AJAXValidation-CustomTheme">Custom Theme</h3><p>In this sample the <a shape="rect" href="struts-2-themes.html">custom theme</a> is based on <em>xhtml</em> theme. It is required to override 3 FTL files.</p><pre>theme.properties</pre><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: text; gutter: false; theme: Default" style="font-size:12px;">parent = xhtml</pre> +</div></div><p> </p><pre>actionerror.ftl</pre><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><#-- + Make sure element is always present. To be filled later via JS. +--> +<ul<#rt/> +<#if parameters.id??> + id="${parameters.id?html}"<#rt/> +</#if> +<#if parameters.cssClass??> + class="${parameters.cssClass?html}"<#rt/> +<#else> + class="errorMessage"<#rt/> +</#if> +<#if parameters.cssStyle??> + style="${parameters.cssStyle?html}"<#rt/> +</#if> +> +<#if (actionErrors?? && actionErrors?size > 0)> + <#list actionErrors as error> + <#if error??> + <li><span><#if parameters.escape>${error!?html}<#else>${error!}</#if></span><#rt/></li><#rt/> + </#if> + </#list> +</#if> +</ul></pre> +</div></div><p> </p><pre>controlfooter.ftl</pre><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">${parameters.after!}<#t/> + </td><#lt/> +</tr> +<#if (parameters.errorposition!"top") == 'bottom'> +<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/> +<#if hasFieldErrors> +<tr errorFor="${parameters.id}"> + <td class="tdErrorMessage" colspan="2"><#rt/> + <#if hasFieldErrors> + <#list fieldErrors[parameters.name] as error> + <div class="errorMessage">${error?html}</div><#t/> + </#list> + </#if> + </td><#lt/> +</tr> +</#if> +</#if> + +</pre> +</div></div><p> </p><pre>controlheader-core.ftl</pre><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> <#-- + Always include elements to show errors. They may be filled later via AJAX. +--> +<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/> +<#if (parameters.errorposition!"top") == 'top'> +<tr errorFor="${parameters.id}"> + <td class="tdErrorMessage" colspan="2" data-error-for-fieldname="${parameters.name}"><#rt/> + <#if hasFieldErrors> + <#list fieldErrors[parameters.name] as error> + <div class="errorMessage">${error?html}</div><#t/> + </#list> + </#if> + </td><#lt/> +</tr> +</#if> +<#if !parameters.labelposition?? && (parameters.form.labelposition)??> +<#assign labelpos = parameters.form.labelposition/> +<#elseif parameters.labelposition??> +<#assign labelpos = parameters.labelposition/> +</#if> +<#-- + if the label position is top, + then give the label it's own row in the table +--> +<tr> +<#if (labelpos!"") == 'top'> + <td class="tdLabelTop" colspan="2"><#rt/> +<#else> + <td class="tdLabel"><#rt/> +</#if> +<#if parameters.label??> + <label <#t/> +<#if parameters.id??> + for="${parameters.id?html}" <#t/> +</#if> +<#if hasFieldErrors> + class="errorLabel"<#t/> +<#else> + class="label"<#t/> +</#if> + ><#t/> +<#if parameters.required!false && parameters.requiredPosition!"right" != 'right'> + <span class="required">*</span><#t/> +</#if> +${parameters.label?html}<#t/> +<#if parameters.required!false && parameters.requiredPosition!"right" == 'right'> + <span class="required">*</span><#t/> +</#if> +${parameters.labelseparator!":"?html}<#t/> +<#include "/${parameters.templateDir}/${parameters.expandTheme}/tooltip.ftl" /> +</label><#t/> +</#if> + </td><#lt/> +<#-- add the extra row --> +<#if (labelpos!"") == 'top'> +</tr> +<tr> +</#if> + +</pre> +</div></div><h3 id="AJAXValidation-CSS">CSS</h3><p>To show users some nice visual feedback while waiting for AJAX response you can use a little CSS. Remember to include the referenced <em>indicator.gif</em>.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: css; gutter: false; theme: Default" style="font-size:12px;">.ajaxVisualFeedback { + width: 16px; + height: 16px; + background-image: url('../images/indicator.gif'); + background-repeat: no-repeat; + float: right; +}</pre> +</div></div><p> </p><h3 id="AJAXValidation-JavaScript">JavaScript</h3><p>Now this is where the magic happens. Here <em>jQuery</em> is used to register an eventhandler which intercepts form submits. It takes care of hiding validation errors that might be present, submit the form via AJAX and handle JSON responses.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: js; gutter: false; theme: Default" style="font-size:12px;"> /** + * Validates form per AJAX. To be called as onSubmit handler. + * + * @param event onSubmit event + */ +function ajaxFormValidation(event) { + event.preventDefault(); + _removeValidationErrors(); + var _form = $(event.target); + var _formData = _form.serialize(true); + // prepare visual feedback + // you may want to use other elements here + var originalButton = _form.find('.btn-primary'); + // note: jQuery returns an array-like object + if (originalButton && originalButton.length && originalButton.length > 0) { + originalButton.hide(); + var feedbackElement = $('<div class="ajaxVisualFeedback"></div>').insertAfter(originalButton); + var restoreFunction = function() { + originalButton.show(); + feedbackElement.remove(); + } + } + var options = { + data: 'struts.enableJSONValidation=true&struts.validateOnly=false&' + _formData, + async: true, + processData: false, + type: 'POST', + success: function (response, statusText, xhr) { + if (response.location) { + // no validation errors + // action has been executed and sent a redirect URL wrapped as JSON + // cannot use a normal http-redirect (status-code 3xx) as this would be followed by browsers and would not be available here + // follow JSON-redirect + window.location.href = response.location; + } else { + if (restoreFunction) { + restoreFunction(); + } + _handleValidationResult(_form, response); + } + }, + error: function(xhr, textStatus, errorThrown) { + if (restoreFunction) { + restoreFunction(); + } + // struts sends status code 400 when validation errors are present + if (xhr.status === 400) { + _handleValidationResult(_form, JSON.parse(xhr.responseText)) + } else { + // a real error occurred -> show user an error message + _handleValidationResult(_form, {errors: ['Network or server error!']}) + } + } + } + // send request, after delay to make sure everybody notices the visual feedback :) + window.setTimeout(function() { + var url = _form[0].action; + jQuery.ajax(url, options); + }, 1000); +} +/** + * Removes validation errors from HTML DOM. + */ +function _removeValidationErrors() { + // action errors + // you might want to use a custom ID here + $('ul.errorMessage li').remove(); + // field errors + $('div.errorMessage').remove(); +} +/** + * Incorporates validation errors in HTML DOM. + * + * @param form Form containing errors. + * @param errors Errors from server. + */ +function _handleValidationResult(form, errors) { + // action errors + if (errors.errors) { + // you might want to use a custom ID here + var errorContainer = $('ul.errorMessage'); + $.each(errors.errors, function(index, errorMsg) { + var li = $('<li><span></span></li>'); + li.text(errorMsg); // use text() for security reasons + errorContainer.append(li); + }); + } + // field errors + if (errors.fieldErrors) { + $.each(errors.fieldErrors, function(fieldName, errorMsg) { + var td = $('td[data-error-for-fieldname="' + fieldName + '"]'); + if (td) { + var div = $('<div class="errorMessage"></div>'); + div.text(errorMsg); // use text() for security reasons + td.append(div); + } + }); + } +} +// register onSubmit handler +$(window).bind('load', function() { + $('form').bind('submit', ajaxFormValidation); +});</pre> +</div></div><p> </p><h2 id="AJAXValidation-Howitworks">How it works</h2><p><em>jsonValidation</em> interceptor must be placed on a stack, following the <em>validation</em> interceptor. The interceptor itself won't perform any validation, but will check for validation errors on the action being invoked (assuming that the action is ValidationAware).</p><p>If you just want to use AJAX validation, without knowing the implementation details, you can skip this section.</p><p>When the <em>jsonValidation</em> interceptor is invoked, it will look for a parameter named <em>struts.enableJSONValidation</em>, this parameter <strong>must</strong> be set to <em>true</em>, otherwise the interceptor won't do anything. Then the interceptor will look for a parameter named <em>struts.validateOnly</em>, if this parameter exists, is set to <em>true</em>, and there are validation errors (o action errors) they will be serialized into JSON in the form:</p><div class="code panel pdl" style="border-width : 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: javascript; gutter: false; theme: Default" style="font-size:12px;">{ + "errors": ["Global Error 1", "Global Error 2"], + "fieldErrors": { + "field1": ["Field 1 Error 1", "Field 1 Error 2"], + "field1": ["Field 2 Error 1", "Field 2 Error 2"] + } +} +</pre> +</div></div><p>If the action implements the <em>ModelDrive</em> interface, "model." will be stripped from the field names in the returned JSON. If validation succeeds (and <em>struts.validateOnly</em> is true), an empty JSON string will be returned:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: javascript; gutter: false; theme: Default" style="font-size:12px;">{} +</pre> +</div></div><p>If <em>struts.validateOnly</em> is false the action and result are executed. In this case <em>jsonActionRedirect</em> result is very useful. It creates a JSON response in the form:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: javascript; gutter: false; theme: Default" style="font-size:12px;">{"location": "<url to be loaded next>"} +</pre> +</div></div><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Remember to set struts.enableJSONValidation=true in the request to enable AJAX validation</p></div></div><h2 id="AJAXValidation-JSONValidationInterceptorparameters">JSONValidationInterceptor parameters</h2><p>The following request parameters can be used to enable exposing validation errors:</p><ul style="list-style-type: square;"><li><strong>struts.enableJSONValidation</strong> - a request parameter must be set to <strong>true</strong> to use this interceptor</li><li><strong>struts.validateOnly</strong> - If the request has this parameter, execution will return after validation (action won't be executed). If <strong>struts.validateOnly</strong> is set to false you may want to use <a shape="rect" class="createlink" href="https://cwiki .apache.org/confluence/pages/createpage.action?spaceKey=WW&title=JSONActionRedirectResult&linkCreation=true&fromPageId=13850">JSONActionRedirectResult</a></li><li><strong>struts.JSONValidation.no.encoding</strong> - If the request has this parameter set to<strong> true,</strong> the character encoding will <strong>NOT</strong> be set on the response - is needed in portlet environment</li></ul><p>You can override names of these parameters by specifying the following parameters when setting up a stack:</p><ul style="list-style-type: square;"><li><strong>validateJsonParam</strong> - to override name of <strong>struts.enableJSONValidation</strong><strong><br clear="none"></strong></li><li><strong>validateOnlyParam</strong> - to override name of <strong>struts.validateOnly</strong></li><li><strong>noEncodingSetParam</strong> - to override name of <strong>struts.JSONValidation.no.encoding</strong></li><li><strong>validationFailedStatus</strong> - status to be se t on response when there are validation errors, by default <strong>400</strong></li></ul><p><strong><br clear="none"></strong></p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"> Parameters overriding is available since Struts 2.5.9</div></div><h2 id="AJAXValidation-FlowchartofAJAXvalidation">Flow chart of AJAX validation</h2><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Some details are omitted, like results used.</p></div></div><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-info rmation-macro-body"><p>As explained above: there is a case where form is submitted twice, one time as AJAX with validation only and another time as usual submit.</p></div></div><p><a shape="rect" href="ajax-validation.data/struts2-ajax-vali-flow.png?version=2&modificationDate=1454052624000&api=v2" data-linked-resource-id="61338002" data-linked-resource-version="2" data-linked-resource-type="attachment" data-linked-resource-default-alias="struts2-ajax-vali-flow.png" data-nice-type="Image" data-linked-resource-content-type="image/png" data-linked-resource-container-id="13850" data-linked-resource-container-version="47"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image" src="ajax-validation.data/struts2-ajax-vali-flow.png"></span></a></p><p> </p></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html>
http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/ajax.html ---------------------------------------------------------------------- diff --git a/content/docs/ajax.html b/content/docs/ajax.html new file mode 100644 index 0000000..42fd497 --- /dev/null +++ b/content/docs/ajax.html @@ -0,0 +1,202 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>AJAX</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="guides.html">Guides</a> > <a href="core-developers-guide.html">Core Developers Guide</a> > <a href="ajax.html">AJAX</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">AJAX</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=34512"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=34512">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=34512"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=34512">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=34512"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=34512">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"><p>AJAX is an acronym for Asynchronous JavaScript and XML. Essentially, a JavaScript can make a HTTP request and update portions of a page directly, without going through a conventional POST or GET and refreshing the entire page. Better yet, a page can contain several JavaScripts making simultaneous (asynchronous) requests.</p><p>The key point is that when a script makes an "Ajax request" (XHR), the server doesn't know it came from a script, and handles it like any other request. One reason Ajax is so successful is that it works just fine with existing server technologies, including Struts.</p><p>It's not the Ajax request that is different, but the Ajax response. Instead of returning an entire page for the browser to display (or redisplay), an Ajax response will just return a portion of a page. The response can take the form of XML, or HTML, or plain text, another script, or whatever else the calling script may want.</p><p>Both Struts 1 and St ruts 2 can return any type of response. We are not limited to forwarding to a server page. In Struts 1, you can just do something like:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">response.setContentType("text/html"); +PrintWriter out = response.getWriter(); +out.println("Hello World! This is an AJAX response from a Struts Action."); +out.flush(); +return null; +</pre> +</div></div><p>In Struts 2, we can do the same thing with a Stream result.</p><div class="confluence-information-macro confluence-information-macro-note"><p class="title">There are easier ways!</p><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Using a Struts 2 plugin (e.g., <a shape="rect" href="json-plugin.html">JSON plugin</a>, jQuery plugin, etc.) is, in general, preferred to writing the response directly from within an action. See sections following this for further details.</p></div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Struts 2 Stream result Action</b></div><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package actions; + +import java.io.InputStream; +import java.io.StringBufferInputStream; +import com.opensymphony.xwork2.ActionSupport; + +public class TextResult extends ActionSupport { + private InputStream inputStream; + public InputStream getInputStream() { + return inputStream; + } + + public String execute() throws Exception { + inputStream = new ByteArrayInputStream("Hello World! This is a text string response from a Struts 2 Action.".getBytes("UTF-8")); + return SUCCESS; + } +} +</pre> +</div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Struts 2 Configuring the TextResult Action</b></div><div class="codeContent panelContent pdl"> +<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><action name="text-result" class="actions.TextResult"> + <result type="stream"> + <param name="contentType">text/html</param> + <param name="inputName">inputStream</param> + </result> +</action> +</pre> +</div></div><p><img class="emoticon emoticon-tick" src="https://cwiki.apache.org/confluence/s/en_GB/5982/f2b47fb3d636c8bc9fd0b11c0ec6d0ae18646be7.1/_/images/icons/emoticons/check.png" data-emoticon-name="tick" alt="(tick)"> Struts 2 can also return a JSON (JavaScript Object Notation) response, using a <a shape="rect" class="external-link" href="http://cwiki.apache.org/S2PLUGINS/json-plugin.html">plugin</a>.</p><p>On the client side, there are two basic strategies, which can be mixed and matched.</p><p>First, you can use some type of JSP tag. Here, you don't have to know very much at all about Ajax or JavaScript. The taglib does all the work, and you just have to figure out how to use the taglib. The standard Struts 2 taglib includes several <a shape="rect" href="ajax-tags.html">Ajax JSP tags</a>, and many third-party libraries are available, including:</p><ul><li><a shape="rect" class="external-link" href="http://ajaxtags.sourceforge.net/" rel="nofollow">Ajax Tags</a></li><li><a sha pe="rect" class="external-link" href="http://javawebparts.sourceforge.net/" rel="nofollow">AjaxParts Taglib</a></li><li><a shape="rect" class="external-link" href="http://servletsuite.blogspot.com/2006/06/coldtags-suite-ajax-edition.html" rel="nofollow">ColdTags Suite</a></li><li><a shape="rect" class="external-link" href="http://www.jenkov.com/prizetags/introduction.tmpl" rel="nofollow">Prize Tags</a></li><li><a shape="rect" class="external-link" href="http://json-taglib.sourceforge.net/" rel="nofollow">JSON-taglib</a></li></ul><p>Alternatively, you can use a plain-old Ajax widget on a plain-old HTML page, using libraries like <a shape="rect" class="external-link" href="http://dojotoolkit.org/" rel="nofollow">Dojo</a>, <a shape="rect" class="external-link" href="http://jquery.com/" rel="nofollow">JQuery</a>, or <a shape="rect" class="external-link" href="http://developer.yahoo.com/yui/" rel="nofollow">YUI</a>, and the StreamResult or the <a shape="rect" class="external-link" href=" http://cwiki.apache.org/S2PLUGINS/json-plugin.html">JSON Plugin</a>. Here, the sky's the limit, but you actually have to learn something about JavaScript as a language.</p><h2 id="AJAX-AjaxPlugins">Ajax Plugins</h2><p>While Struts works fine with Ajax out-of-the-box, for added value, several Ajax-centric plugins are available.</p><h3 id="AJAX-AjaxTagPlugins">Ajax Tag Plugins</h3><ul><li><strong>jQuery</strong> - The <a shape="rect" class="external-link" href="https://github.com/struts-community-plugins/struts2-jquery" rel="nofollow">jQuery Plugin</a> provide ajax functionality and UI Widgets an JavaScript Grid based on the jQuery javascript framework.<strong><br clear="none"></strong></li><li><strong>Ajax Parts</strong> - The <a shape="rect" class="external-link" href="http://code.google.com/p/struts2ajaxpartstaglibplugin/" rel="nofollow">AjaxParts Taglib (APT)</a> is a component of the Java Web Parts (JWP) project (<a shape="rect" class="external-link" href="http://j avawebparts.sourceforge.net" rel="nofollow">http://javawebparts.sourceforge.net</a>) that allows for 100% declarative (read: no Javascript coding required!) AJAX functionality within a Java-based webapp.</li><li><strong>Dojo</strong> - The <a shape="rect" href="ajax-tags.html">Ajax Tags Dojo Plugin</a> was represented as a theme for Struts 2.0. For Struts 2.1, the Dojo tags are bundled as a plugin until version 2.3.x. Since version 2.5 this plugin is not part of th Struts2 distribution anymore </li><li><strong>YUI</strong> - The <a shape="rect" class="external-link" href="https://code.google.com/p/struts2yuiplugin/" rel="nofollow">Yahoo User Interface (YUI) Plugin</a> has only a few tags are available so far, but the YUI tags tend to be easier to use than the Dojo versions.</li></ul><h3 id="AJAX-OtherAjaxPlugins">Other Ajax Plugins</h3><ul><li><strong>Ajax File Upload</strong> - With the <a shape="rect" class="external-link" href="http://www.davidjc.com/ajaxfileupload/demo!inpu t.action" rel="nofollow">Ajax File Upload Plugin</a> we can upload a file to the server and asynchronously monitor its progress.</li><li><strong>GWT</strong> - The <a shape="rect" class="external-link" href="https://code.google.com/p/struts2gwtplugin/" rel="nofollow">Google Web Toolkit Plugin</a> exposes Struts 2 actions to the GWT RPC mechanism.</li><li><strong>JSON</strong> - The <a shape="rect" href="json-plugin.html">JSON Plugin</a> serializes Actions properties into JSON, making it easy to respond to JavaScript requests.</li></ul><p>See the <a shape="rect" class="external-link" href="http://cwiki.apache.org/S2PLUGINS/home.html">Struts Plugin Repository</a> for a complete list of Struts 2 plugins.</p><h2 id="AJAX-AjaxResultswithJSP">Ajax Results with JSP</h2><p>While server pages are most often used to generate HTML, we can use server pages to create other types of data streams. Here's an example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader p anelHeader pdl" style="border-bottom-width: 1px;"><b>book.jsp</b></div><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"><%@ page import="java.util.Iterator, + java.util.List, + com.esolaria.dojoex.Book, + com.esolaria.dojoex.BookManager" %> +<% + String bookIdStr = request.getParameter("bookId"); + int bookId = (bookIdStr == null || "".equals(bookIdStr.trim())) + ? 0 : Integer.parseInt(bookIdStr); + Book book = BookManager.getBook(bookId); + if (book != null) { + out.println(book.toJSONString()); + System.out.println("itis: " + book.toJSONString()); + } +%> +</pre> +</div></div><p>In the code example, we use <code>System.out.println</code> to return a JSON data stream as the response. For more about this technique, see the article <a shape="rect" class="external-link" href="http://today.java.net/pub/a/today/2006/04/27/building-ajax-with-dojo-and-json.html" rel="nofollow">Using Dojo and JSON to Build Ajax Applications</a>.</p><h2 id="AJAX-Next:">Next: <a shape="rect" href="dependency-injection.html">Dependency Injection</a></h2></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html> http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/alias-interceptor.html ---------------------------------------------------------------------- diff --git a/content/docs/alias-interceptor.html b/content/docs/alias-interceptor.html new file mode 100644 index 0000000..6de478d --- /dev/null +++ b/content/docs/alias-interceptor.html @@ -0,0 +1,189 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>Alias Interceptor</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="guides.html">Guides</a> > <a href="core-developers-guide.html">Core Developers Guide</a> > <a href="interceptors.html">Interceptors</a> > <a href="alias-interceptor.html">Alias Interceptor</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">Alias Interceptor</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=14046"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=14046">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=14046"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=14046">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=14046"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=14046">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"> +<p>The aim of this Interceptor is to alias a named parameter to a different named parameter. By acting as the glue +between actions sharing similar parameters (but with different names), it can help greatly with action chaining.</p> + +<p></p><p>Action's alias expressions should be in the form of <code>#{ "name1" : "alias1", "name2" : "alias2" }</code>. +This means that assuming an action (or something else in the stack) has a value for the expression named <i>name1</i> and the +action this interceptor is applied to has a setter named <i>alias1</i>, <i>alias1</i> will be set with the value from +<i>name1</i>. +</p> + + +<h2 id="AliasInterceptor-Parameters">Parameters</h2> + + +<p></p><ul></ul><p></p><ul><li>aliasesKey (optional) - the name of the action parameter to look for the alias map (by default this is +<i>aliases</i>).</li></ul><p></p> + + +<h2 id="AliasInterceptor-ExtendingtheInterceptor">Extending the Interceptor</h2> + + +<p>This interceptor does not have any known extension points.</p> + + +<h2 id="AliasInterceptor-Examples">Examples</h2> + +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<script class="brush: xml; gutter: false; theme: Default" type="syntaxhighlighter"><![CDATA[ +<action name="someAction" class="com.examples.SomeAction"> + <!-- The value for the foo parameter will be applied as if it were named bar --> + <param name="aliases">#{ 'foo' : 'bar' }</param> + + <interceptor-ref name="alias"/> + <interceptor-ref name="basicStack"/> + <result name="success">good_result.ftl</result> +</action> +]]></script> +</div></div></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html> http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/alt-syntax.html ---------------------------------------------------------------------- diff --git a/content/docs/alt-syntax.html b/content/docs/alt-syntax.html new file mode 100644 index 0000000..99d8610 --- /dev/null +++ b/content/docs/alt-syntax.html @@ -0,0 +1,195 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>Alt Syntax</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="alt-syntax.html">Alt Syntax</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">Alt Syntax</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13974"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13974">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13974"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13974">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13974"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13974">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"> + +<p>The <em>altSyntax</em> is an option that can be defined in <a shape="rect" href="strutsproperties.html">struts.properties</a>. By default it is set to true and it is <strong>strongly</strong> recommend you do not change that unless you are upgrading from WebWork 2.1.7 or previous versions.</p> + +<div class="confluence-information-macro confluence-information-macro-tip"><p class="title">Migration tip</p><span class="aui-icon aui-icon-small aui-iconfont-approve confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>You can also turn on the altSyntax on a per-page basis by using the <a shape="rect" href="set.html">set</a> tag. Simply set the name <em>useAltSyntax</em> to the value <em>true</em>. From this point on, all tags will use the altSyntax for the rest of the request.</p></div></div> + +<p>The altSyntax changes the behavior of how tags are interpreted. Instead of evaluating each tag parameter against the value stack and needing single quotes to mark string literals, only marked expressions are evaluated.</p> + +<p>Example:</p> + +<p>the following code uses the <a shape="rect" href="tag-syntax.html">Tag Syntax</a>:</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +<s:iterator value="cart.items"> + ... + <s:textfield label="'Cart item No.' + #rowstatus.index + ' note'" + name="'cart.items[' + #rowstatus.index + '].note'" + value="note" /> +</s:iterator> +</pre> +</div></div> + +<p>this is somewhat counter intuitive to normal HTML tag behaviour, and you get loads of single quotes. Now the same example in altSyntax:</p> + +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +<s:iterator value="cart.items"> + ... + <s:textfield label="Cart item No. %{#rowstatus.index} note" + name="cart.items[%{#rowstatus.index}].note" + value="%{note}" /> +</s:iterator> +</pre> +</div></div> + +<p>Only expressions enclosed with %{} are evaluated. The code is shorter and clearer, very similar to JSTL EL usage. Quoting problems, eg. with javascript function calls, are avoided.</p> + +<p>In order to fully understand why this option exists and what the differences are, it is best to get a bit of history about WebWork.</p> + +<div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>If you are <em>not</em> upgrading from WebWork 2.1.7 or previous versions and you don't care about the history of WebWork's evolution, you can skip this section. See the <a shape="rect" href="tag-syntax.html">Tag Syntax</a> section for more information on the standard tag syntax support</p></div></div> + +<h1 id="AltSyntax-History">History</h1> + +<p>In WebWork 2.1.4, the altSyntax option was introduced. The book, WebWork in Action, while based around WebWork 2.1.7, was entirely written with the assumption that the altSyntax was enabled. As of WebWork 2.2, the altSyntax is turned on by default and eventually the old syntax will no longer be supported and will be removed from the code.</p></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html>