You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@click.apache.org by sa...@apache.org on 2010/09/02 14:37:24 UTC
svn commit: r991917 - in /click/trunk/click/documentation/xdocs/src:
docbook/click/chapter-ajax.xml docbook/click/click-book.xml images/ajax/
images/ajax/ajax-class-diagram.png
images/ajax/ajax-request-sequence-diagram.png
Author: sabob
Date: Thu Sep 2 12:37:24 2010
New Revision: 991917
URL: http://svn.apache.org/viewvc?rev=991917&view=rev
Log:
added Ajax chapter
Added:
click/trunk/click/documentation/xdocs/src/docbook/click/chapter-ajax.xml
click/trunk/click/documentation/xdocs/src/images/ajax/
click/trunk/click/documentation/xdocs/src/images/ajax/ajax-class-diagram.png (with props)
click/trunk/click/documentation/xdocs/src/images/ajax/ajax-request-sequence-diagram.png (with props)
Modified:
click/trunk/click/documentation/xdocs/src/docbook/click/click-book.xml
Added: click/trunk/click/documentation/xdocs/src/docbook/click/chapter-ajax.xml
URL: http://svn.apache.org/viewvc/click/trunk/click/documentation/xdocs/src/docbook/click/chapter-ajax.xml?rev=991917&view=auto
==============================================================================
--- click/trunk/click/documentation/xdocs/src/docbook/click/chapter-ajax.xml (added)
+++ click/trunk/click/documentation/xdocs/src/docbook/click/chapter-ajax.xml Thu Sep 2 12:37:24 2010
@@ -0,0 +1,821 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<chapter id="chapter-ajax" remap="h1">
+ <title>Ajax</title>
+
+ <sect1 id="ajax-overview" remap="h2">
+ <title>Ajax Overview</title>
+
+ <para>Ajax is a method of using JavaScript to perform a GET or POST request
+and return a result without reloading the whole page.
+ </para>
+
+ <para>For an introduction on Ajax please see the following articles:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><ulink url="http://www.w3schools.com/Ajax/default.asp">http://www.w3schools.com/Ajax/default.asp</ulink></para>
+ </listitem>
+
+ <listitem>
+ <para><ulink url="http://en.wikipedia.org/wiki/AJAX">http://en.wikipedia.org/wiki/AJAX</ulink></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Ajax is a client-side technology for creating interactive web applications.
+ The JavaScript <literal>XMLHttpRequest</literal> object is used to perform GET
+ and POST requests and the server can send back a response that can be processed
+ in the browser.
+ </para>
+
+ <para>Click on the other hand is a server-side technology that can handle and
+ process incoming Ajax requests and send a response back to the browser.
+ </para>
+
+ <para><emphasis role="bold">Please note:</emphasis> Click is responsible
+ for handling server-side requests. It is up to you to develop the client-side
+ logic necessary to make the Ajax request, process the server response
+ and handle errors. Fortunately this step is quite easy since Click is a
+ stateless framework and Page URLs are obvious and transparent.
+ </para>
+
+ <para>It is also possible to write custom Behaviors (covered later) that renders
+ the client-side code necessary to initiate Ajax requests and handle Ajax responses
+ and errors. In fact once you become familiar Click's Ajax handling, you will
+ likely create custom Behaviors to streamline and encapsulate your client-side
+ code.
+ </para>
+
+ <para><emphasis role="bold">Also note:</emphasis> Click doesn't care what
+ client-side technology you use. You can use pure JavaScript or one of the
+ popular JavaScript libraries such as:
+ <ulink url="http://www.jquery.com">jQuery</ulink>,
+ <ulink url="http://www.prototypejs.org/">Prototype</ulink>,
+ <ulink url="http://mootools.net/">MooTools</ulink> to name a few.
+ </para>
+
+ <para>In this chapter we'll look at the Ajax support provided by Click. There
+ are two basic ways to handle and process Ajax requests:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para><link linkend="ajax-behaviors">Ajax Behaviors</link> - a Behavior
+ can change how a Control behave at runtime, allowing the Control to handle
+ and process Ajax requests. Behaviors are added to Controls through
+ <ulink url="../../click-api/org/apache/click/control/AbstractControl.html#addBehavior(org.apache.click.Behavior)">AbstractControl.addBehavior()</ulink>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para><link linkend="ajax-page-action">Page Actions</link> - Page Actions
+ was covered <link linkend="page-actions">earlier</link> and provides a
+ popular way to handle and process Ajax requests
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1 id="ajax-behaviors" remap="h2">
+ <title>Ajax Behaviors</title>
+
+ <para><ulink url="../../click-api/org/apache/click/Behavior.html">Behaviors</ulink>
+ can change how Controls behave at runtime. The default Behavior implementation,
+ <ulink url="../../click-api/org/apache/click/ajax/AjaxBehavior.html">AjaxBehavior</ulink>,
+ can be added to a Control, enabling that control to handle, process and respond
+ to Ajax requests.
+ </para>
+
+ <para>
+ Behaviors are added to controls through
+ <ulink url="../../click-api/org/apache/click/control/AbstractControl.html#addBehavior(org.apache.click.Behavior)">AbstractControl.addBehavior()</ulink>
+ and the same Behavior can be shared by multiple Controls.
+ </para>
+
+ <para>Behaviors provides an
+ <ulink url="../../click-api/org/apache/click/Behavior.html#onAction(org.apache.click.Control)">onAction</ulink>
+ method (similar to <classname>ActionListener</classname>) that is invoked to
+ handle and process the Ajax request. The <methodname>onAction</methodname>
+ method returns an <ulink url="../../click-api/org/apache/click/ActionResult.html">ActionResult</ulink>
+ containing the data rendered to the browser. In addition Behaviors provides
+ <literal>interceptor</literal> methods to decorate and enhance the Control.
+ </para>
+
+ <para>The <classname>Control</classname>,
+ <classname>Behavior</classname> and <classname>ActionResult</classname>
+ class is depicted in the figure below.
+ </para>
+
+ <figure id="ajax-behavior-class-diagram">
+ <title>Ajax Behavior Class Diagram</title>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/ajax/ajax-class-diagram.png" format="PNG" scale="65"/>
+ </imageobject>
+ </inlinemediaobject>
+ </figure>
+
+ <para>The Control contains a <classname>Set</classname> that holds the
+ <classname>Behaviors</classname> added to the <classname>Control</classname>.
+ The Control interface exposes the following methods for handling Ajax requests:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Control.html#getBehaviors()">getBehaviors()</ulink>
+ - returns the Control's Set of Behaviors
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Control.html#hasBehaviors()">hasBehaviors()</ulink>
+ - returns true if the Control has any Behaviors.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Control.html#isAjaxTarget(org.apache.click.Context)">isAjaxTarget()</ulink>
+ - Returns true if the control is the Ajax request <literal>target</literal>,
+ false otherwise. The <literal>Ajax target control</literal> is the Control
+ which <methodname>onProcess</methodname> method will be invoked. The most
+ common way to target a specific server side control is to give it an
+ <ulink url="../../click-api/org/apache/click/control/AbstractControl.html#setId(java.lang.String)">HTML ID</ulink>
+ attribute, that is then passed as an Ajax request parameter to the server.
+ More on this later.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The Behavior interface is covered next:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Behavior.html#onAction(org.apache.click.Control)">onAction()</ulink>
+ - the Behavior action method for handling Ajax requests.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Behavior.html#isRequestTarget(org.apache.click.Context)">isRequestTarget()</ulink>
+ - determines whether the behavior is the request target or not. Click
+ will only invoke <methodname>onAction</methodname> if
+ <methodname>isRequestTarget()</methodname> returns true. This method
+ allows for fine grained control over the exection of the <methodname>onAction</methodname>
+ method.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Behavior.html#preResponse(org.apache.click.Control)">preResponse()</ulink>
+ - defines an interceptor method that is invoked before the response is written.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Behavior.html#preGetHeadElements(org.apache.click.Control)">preGetHeadElements()</ulink>
+ - defines an interceptor method that is invoked after <methodname>preResponse()</methodname>
+ but before the <classname>Control</classname> <methodname>getHeadElements()</methodname>
+ is called.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/Behavior.html#preDestroy(org.apache.click.Control)">preDestroy()</ulink>
+ - defines an interceptor method that is invoked before the
+ <classname>Control</classname> <methodname>onDestroy()</methodname>
+ event handler. This interceptor method allows the behavior to cleanup
+ any resources.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The <classname>Behavior</classname> provides an <methodname>onAction</methodname>
+ method for handling Ajax requests. The <methodname>onAction</methodname>
+ method returns an <classname>ActionResult</classname> containing the data that
+ is rendered to the browser.
+ </para>
+
+ <para>The <methodname>isRequestTarget</methodname> method controls whether or
+ not the <methodname>onAction</methodname> method should be invoked.
+ <methodname>isRequestTarget()</methodname> is typically used to target the
+ Behavior for specific JavaScript events. For example a Behavior might only
+ handle <literal>onclick</literal> or <literal>onblur</literal> JavaScript events.
+ For this to work the client-side code initiating the Ajax request should pass
+ the JavaScript event to the server.
+ </para>
+
+ <para>The <classname>Behavior</classname> also provides a number of interceptor
+ methods for specific <classname>Control</classname> life cycle events. These
+ interceptor methods can be implemented to process and decorate the control or
+ its children.
+ </para>
+
+ <para>Lastly the <classname>ActionResult</classname> methods are shown below:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/ActionResult.html#setContent(java.lang.String)">setContent(String)</ulink>
+ - set the String content to render to the browser
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/ActionResult.html#setBytes(byte[])">setBytes(byte[])</ulink>
+ - set the byte array to render to the browser
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/ActionResult.html#setBytes(byte[])">setTemplate(String)</ulink>
+ - set the name of the Velocity (or Freemarker) template to render to
+ the browser
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/ActionResult.html#setModel(java.util.Map)">setModel(Map)</ulink>
+ - set the Velocity (or Freemarker) template model
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <ulink url="../../click-api/org/apache/click/ActionResult.html#setModel(java.util.Map)">setModel(Map)</ulink>
+ - set the ActionResult content type, for example: <literal>text/html</literal>,
+ <literal>text/xml</literal>, <literal>application/json</literal> etc.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>An ActionResult is returned by the Behavior <methodname>onAction</methodname>
+ method and contains the data to render to the browser. ActionResult can return
+ any response to the browser: String, byte array or a template.
+ </para>
+
+ </sect1>
+
+ <sect1 id="ajax-behavior-execution" remap="h2">
+ <title>Ajax Behavior Execution</title>
+
+ <para>The execution sequence for an <classname>Ajax Behavior</classname>
+ being processed and rendered is illustrated in the figure below. You'll note
+ that it is similar to a normal HTTP request flow. The main differences are that
+ Ajax requests do not have an onGet or onRender event. Another difference
+ is that only the <literal>Ajax target Control</literal> is processed.
+ </para>
+
+ <figure id="ajax-behavior-sequence-diagram">
+ <title>Ajax Behavior Sequence Diagram</title>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/ajax/ajax-request-sequence-diagram.png" format="PNG" scale="58"/>
+ </imageobject>
+ </inlinemediaobject>
+ </figure>
+
+ <para>Stepping through this Ajax GET request sequence, first a new Page
+ instance is created.
+ </para>
+
+ <para>Then the <methodname>onSecurityCheck()</methodname> handler is executed
+ to authorize access to the page, and if necessary abort further processing.
+ If the request is aborted for an Ajax request, no response is rendered to
+ the browser. If you want to render a response you need to write to the
+ <classname>HttpServletResponse</classname> directly or create and
+ render an <classname>ActionResult</classname> yourself.
+ </para>
+
+ <para>The next method invoked is <methodname>onInit()</methodname> to initialize,
+ create and setup controls and <classname>Behaviors</classname>.
+ <methodname>onInit</methodname> is an ideal place to add <classname>Behaviors</classname>
+ to <classname>Controls</classname>. When a Behavior is added to a Control that
+ Control is automatically registered with the ClickServlet as a potential
+ <literal>Ajax target control</literal>.
+ </para>
+
+ <para>The next step is to find and process the <literal>Ajax target control</literal>.
+ First the ClickServlet needs to determine which Control is the Ajax target.
+ To resolve the target Control the ClickServlet iterates over all the registered
+ Controls and invokes each Control's method: <methodname>isAjaxTarget()</methodname>.
+ The first control which isAjaxTarget() returns true will be resolved as the
+ Ajax target. The most common way for a Control to be resolved as the Ajax
+ target is to check if its ID attribute is passed as a request parameter. It
+ is then up the client-side JavaScript code that initiated the Ajax request
+ to ensure the Control ID is sent as part of the Ajax request. Note, if the
+ ClickServlet cannot find a target control, no response is rendered.
+ </para>
+
+ <para>If an Ajax target control is found, the ClickServlet will invoke
+ that control's <methodname>onProcess</methodname> method. Other controls are not
+ processed. It is important to note that processing a control for an Ajax request
+ has the same requirements as processing a control for a non-Ajax request.
+ In other words, in addition to the Control ID (or other identifier), the Ajax
+ request must send all the parameters normally expected by the target Control
+ and its children. For example, a Field expects it's <literal>name/value</literal>
+ parameter while an ActionLink expects its <literal>actionLink/name</literal>
+ parameter.
+ </para>
+
+ <para>Next, the target control <classname>Behaviors</classname> are fired.
+ The ClickServlet iterates over the control Behaviors and for each
+ Behavior invoke the method: <methodname>isRequestTarget()</methodname>. Each
+ Behavior which <methodname>isRequestTarget</methodname> method returns true
+ will have their <methodname>onAction</methodname> method invoked to handle
+ the Ajax request. The Behavior <methodname>onAction</methodname> method
+ returns an <classname>ActionResult</classname> that is rendered to the browser.
+ </para>
+
+ <para>Please note: multiple Behaviors can handle the Ajax request, however
+ only the first ActionResult returned will be rendered to the browser. If an
+ onAction method returns null, the ActionResult from the next Behavior onAction
+ method will be used. If all onAction methods returns null, no response is
+ rendered.
+ </para>
+
+ <para>Next the ActionResult is rendered to the browser.</para>
+
+ <para>The final step in this sequence is invoking each control's onDestroy()
+ method and lastly invoke the Page's onDestroy() method.</para>
+ </sect1>
+
+ <sect1 id="first-ajax-example" remap="h2">
+ <title>First Ajax Example</title>
+
+ <para>In this first example we demonstrate how to handle Ajax requests with an
+ <symbol>AjaxBehavior</symbol>. AjaxBehavior is the default implementation of
+ the <classname>Behavior</classname> interface. Below we show the Page class,
+ <classname>AjaxBehaviorPage.java</classname>, and how an
+ <symbol>AjaxBehavior</symbol> is added to an ActionLink called link with an
+ HTML ID <varname>link-id</varname>. The AjaxBehavior <varname>onAction</varname>
+ method will be invoked to handle the Ajax request. The <varname>onAction</varname>
+ method returns an <token>ActionResult</token> that is rendered to the browser.
+ </para>
+
+ <programlisting language="java">public class AjaxBehaviorPage extends BorderPage {
+
+ private static final long serialVersionUID = 1L;
+
+ private ActionLink link = new ActionLink("link", "here");
+
+ public AjaxBehaviorPage() {
+ link.setId("link-id"); <co id="co-link-id" linkends="ca-link-id"/>
+
+ addControl(link);
+
+ // Add an Ajax behavior to the link. The behavior will be invoked when the
+ // link is clicked.
+ link.addBehavior(new <symbol>AjaxBehavior()</symbol> { <co id="co-ajax-behavior" linkends="ca-ajax-behavior"/>
+
+ @Override
+ public <token>ActionResult</token> <varname>onAction</varname>(Control source) { <co id="co-ajax-behavior-method" linkends="ca-ajax-behavior-method"/>
+
+ // Formatted date instance that will be added to the
+ String now = format.currentDate("MMM, yyyy dd HH:MM:ss");
+
+ String msg = "AjaxBehavior <tt>onAction()</tt> method invoked at: " + now;
+
+ // Return an action result containing the message
+ return new <token>ActionResult</token>(msg, ActionResult.HTML); <co id="co-ajax-action-result" linkends="ca-ajax-action-result"/>
+ }
+ });
+ }
+} </programlisting>
+
+ <calloutlist>
+ <callout arearefs="co-link-id" id="ca-link-id">
+ <para>We assign to the ActionLink the HTML ID: <varname>link-id</varname>.
+ The ID will be used to identify the ActionLink as the
+ <literal>Ajax target control</literal>. The client-side JavaScript code
+ is expected to send this ID as an Ajax request parameter.
+ </para>
+ </callout>
+ <callout arearefs="co-ajax-behavior" id="ca-ajax-behavior">
+ <para>Next we add an <symbol>AjaxBehavior</symbol> to the ActionLink.
+ Adding a Behavior to a control will also register that control as a
+ potential <literal>Ajax target control</literal>.
+ </para>
+ </callout>
+ <callout arearefs="co-ajax-behavior-method" id="ca-ajax-behavior-method">
+ <para>We also implement the Behavior <varname>onAction</varname> method
+ in order to handle the Ajax request.
+ </para>
+ </callout>
+ <callout arearefs="co-ajax-action-result" id="ca-ajax-action-result">
+ <para>Lastly we return an <token>ActionResult</token> containing HTML
+ content that is rendered to the browser.
+ </para>
+ </callout>
+ </calloutlist>
+
+ <para>Next we show the Page template <literal>ajax-behavior.htm</literal>,
+ containing the client-side JavaScript code that will initiate an Ajax request.
+ </para>
+
+ <para><emphasis role="bold">Please note:</emphasis> we assume you are familiar
+ with basic JavaScript skills. In this example we use the <ulink url="http://www.jquery.com">jQuery</ulink>
+ JavaScript library, but any other library can be used, even raw JavaScript.
+ Also see the online Click examples for more Ajax examples.
+ </para>
+
+ <programlisting language="javascript"><!-- // $link is a Velocity reference that will render an ActionLink at runtime. -->
+Click $link to call the server using Ajax.
+
+<div id="result">
+ <!-- // Ajax response will be set here -->
+</div>
+
+<!-- // JavaScript code below -->
+
+<!-- // Import the jQuery library -->
+<script type="text/javascript" src="$context/js/jquery.js"></script>
+
+<!-- // The client-side JavaScript for initiating an Ajax request -->
+<script type="text/javascript">
+ // This example uses jQuery for making Ajax requests:
+
+ // Register a function that is invoked as soon as the entire DOM has been loaded
+ jQuery(document).ready(function() { <co id="co-ajax-jq-function" linkends="ca-ajax-jq-function"/>
+
+ // Register a 'click' handler that makes an Ajax request
+ jQuery("#link-id").click(function(event){
+ // Make ajax request
+ makeRequest();
+
+ // Prevent the default browser behavior of navigating to the link
+ return false;
+ })
+ })
+
+ function makeRequest() {
+ // Get a reference to the link
+ var link = jQuery('#link-id');
+
+ // In order for Click to identify the Ajax target, we pass the link ID
+ // attribute as request parameters
+ var extraData = link.attr('id') + '=1'; <co id="co-ajax-link-id" linkends="ca-ajax-link-id"/>
+
+ // The Ajax URL is set to the link 'href' URL which contains all the link default parameters, including it's name/value pair: 'actionLink=link'
+ var url = link.attr('href'); <co id="co-ajax-jq-href" linkends="ca-ajax-jq-href"/>
+
+ jQuery.get(url, extraData, function(data) {
+ // 'data' is the response returned from the server
+
+ // We update the div with the ID 'result' and set its content to the server response
+ jQuery("#result").html("<p>" + data + "</p>"); <co id="co-ajax-jq-response" linkends="ca-ajax-jq-response"/>
+ });
+ }
+</script> </programlisting>
+
+ <calloutlist>
+ <callout arearefs="co-ajax-jq-function" id="ca-ajax-jq-function">
+ <para>We start off with a jQuery <ulink url="http://api.jquery.com/ready/">ready</ulink>
+ function that is executed as soon as the browser DOM has been loaded.
+ This ensures that the function body is executed <literal>before</literal>
+ the page images are downloaded, which leads to a more responsive GUI.
+ </para>
+ </callout>
+ <callout arearefs="co-ajax-link-id" id="ca-ajax-link-id">
+ <para>Next is an important step. We need to pass the link <varname>HTML ID</varname>
+ attribute as request parameters in order for the server to identify <literal>which</literal>
+ server-side control is the <literal>Ajax target</literal>. We use the jQuery
+ <literal>attr</literal> function to lookup the link's <varname>HTML ID</varname>
+ attribute. Click does not care about <literal>value</literal> of the
+ parameter, so we pass in a value of <varname>1</varname>, but any other
+ value could be used.
+ </para>
+ </callout>
+ <callout arearefs="co-ajax-jq-href" id="ca-ajax-jq-href">
+ <para>Next step is also important. We can't just pass in the Control HTML ID.
+ Although the HTML ID identifies which Control is the target control, that
+ only instructs Click to process the control. The Control <methodname>onProcess</methodname>
+ method is where the Control values are bound, validated and action event
+ is fired. So what is needed is to pass all the parameters normally expected
+ by the ActionLink <methodname>onProcess</methodname> method. In the case
+ of ActionLink, that means the Ajax request must include it's <varname>href</varname>
+ parameters. The easiest way to do this is to use jQuery to set the Ajax
+ <literal>URL</literal> to the ActionLink <varname>href</varname> value.
+ </para>
+ </callout>
+ <callout arearefs="co-ajax-jq-response" id="ca-ajax-jq-response">
+ <para>Lastly TODO
+ </para>
+ </callout>
+ </calloutlist>
+
+ <sect2 id="ajax-trace-log" remap="h3">
+ <title>Ajax Trace Log</title>
+
+ <para>Looking at the output log we see the following trace:
+ </para>
+
+ <literallayout>[Click] [debug] GET http://localhost:8080/mycorp/ajax/ajax-behavior.htm
+[Click] [trace] <symbol>is Ajax request</symbol>: <varname>true</varname>
+[Click] [trace] request param: <varname>actionLink=link</varname>
+[Click] [trace] request param: <varname>link-id=1</varname>
+[Click] [trace] invoked: AjaxBehaviorPage.<<init>>
+[Click] [trace] invoked: AjaxBehaviorPage.onSecurityCheck() : true
+[Click] [trace] invoked: AjaxBehaviorPage.onInit()
+[Click] [trace] invoked: 'link' ActionLink.onInit()
+[Click] [trace] <token>the following controls have been registered as potential Ajax targets:</token>
+[Click] [trace] ActionLink: name='link'
+[Click] [trace] invoked: 'link' ActionLink.<symbol>isAjaxTarget()</symbol> : <varname>true</varname> (target Ajax control found)
+[Click] [trace] invoked: 'link' ActionLink.<symbol>onProcess()</symbol> : <varname>true</varname>
+[Click] [trace] <token>processing Behaviors for control: 'link' ActionLink</token>
+[Click] [trace] invoked: AjaxBehaviorPage.1.<symbol>isRequestTarget()</symbol> : <varname>true</varname>
+[Click] [trace] invoked: AjaxBehaviorPage.1.<symbol>onAction()</symbol> : <varname>ActionResult</varname> (ActionResult will be rendered)
+[Click] [info ] <token>renderActionResult</token> (text/html) - 0 ms
+[Click] [trace] invoked: 'link' ActionLink.onDestroy()
+[Click] [trace] invoked: AjaxBehaviorPage.onDestroy()
+[Click] [info ] handleRequest: /ajax/ajax-behavior.htm - 68 ms</literallayout>
+
+ <para>First thing we notice is that the request is recognized as an
+ <symbol>Ajax request</symbol>.
+ </para>
+
+ <para>We can also see from the log that the Ajax request sent the parameters,
+ <varname>link-id=1</varname> and <varname>actionLink=link</varname> to the server.
+ <varname>link-id</varname> is the ActionLink HTML ID attribute that will be used
+ to identify the Control as the <literal>Ajax request target</literal>.
+ </para>
+
+ <para>Next the log prints which controls have been registered as <literal>potential
+ Ajax targets</literal>. In our example we added a Behavior to the ActionLink
+ so the ActionLink is registered as an Ajax target.
+ </para>
+
+ <para>Next the ActionLink#<symbol>isAjaxTarget</symbol> was invoked and because
+ it returned <varname>true</varname>, ActionLink will be set as the
+ <literal>Ajax target control.</literal>
+ </para>
+
+ <para>Having found the <literal>Ajax target</literal>, the ActionLink
+ <symbol>onProcess</symbol> is called.
+ </para>
+
+ <para>Next, the log shows it found the <literal>target Behavior</literal>.
+ by invoking Behavior#<symbol>isRequestTarget</symbol> method, which
+ also returned <varname>true</varname>.
+ </para>
+
+ <para>The Behavior#<symbol>onAction</symbol> is invoked which returns an
+ <varname>ActionResult</varname>.
+ </para>
+
+ <para>Finally the <varname>ActionResult</varname> is rendered to the browser.
+ </para>
+ </sect2>
+
+ <sect2 id="ajax-trace-log-no-target-control" remap="h3">
+ <title>Ajax Trace Log - No Ajax Target Control Found</title>
+
+ <para>Below we show a log trace where no <literal>Ajax target control</literal>
+ is found. The most common reason that can happen is if the JavaScript code
+ that initiates the Ajax request does not send the necessary request parameters
+ to identify the <literal>Ajax target control</literal>. Another common reason
+ is if no Behavior was added to a Control.
+ </para>
+
+ <literallayout>[Click] [debug] GET http://localhost:8080/mycorp/ajax/ajax-behavior.htm
+[Click] [trace] <symbol>is Ajax request</symbol>: <varname>true</varname>
+[Click] [trace] request param: <varname>actionLink=link</varname>
+[Click] [trace] invoked: AjaxBehaviorPage.<<init>>
+[Click] [trace] invoked: AjaxBehaviorPage.onSecurityCheck() : true
+[Click] [trace] invoked: AjaxBehaviorPage.onInit()
+[Click] [trace] invoked: 'link' ActionLink.onInit()
+[Click] [trace] <token>the following controls have been registered as potential Ajax targets:</token>
+[Click] [trace] ActionLink: name='link'
+[Click] [trace] <symbol>*no*</symbol> target control was found for the Ajax request
+[Click] [trace] invoked: 'link' ActionLink.onDestroy()
+[Click] [trace] invoked: AjaxBehaviorPage.onDestroy()
+[Click] [info ] handleRequest: /ajax/ajax-behavior.htm - 87 ms</literallayout>
+
+ <para>Notice from the log that the only Ajax request parameters sent was
+ <varname>actionLink=link</varname>.
+ </para>
+
+ <para>Next the log prints which controls have been registered as <literal>potential
+ Ajax targets</literal>. In our example we added a Behavior to the ActionLink
+ so the ActionLink is registered as an Ajax target.
+ </para>
+
+ <para>Next we see that <symbol>*no*</symbol> Ajax target control was found.
+ The reason is because the ActionLink ID attribute, <literal>link-id</literal>,
+ does not match the incoming request parameter, <literal>actionLink=link</literal>,
+ hence the ActionLink was not identified as the <literal>Ajax request target</literal>
+ and no response is rendered.
+ </para>
+ </sect2>
+
+ <sect2 id="ajax-trace-log-no-target-behavior" remap="h3">
+ <title>Ajax Trace Log - No Target Behavior Found</title>
+
+ <para>Below we show a log trace where a no <literal>target behavior</literal>
+ is found. The reason this can happen is if the <symbol>isRequestTarget</symbol>
+ of the <classname>Behaviors</classname> added to the Control returns false.
+ </para>
+
+ <literallayout>[Click] [debug] GET http://localhost:9999/mycorp/ajax/ajax-behavior.htm
+[Click] [trace] <symbol>is Ajax request</symbol>: <varname>true</varname>
+[Click] [trace] request param: <varname>actionLink=link</varname>
+[Click] [trace] request param: <varname>link-id=1</varname>
+[Click] [trace] invoked: AjaxBehaviorPage.<<init>>
+[Click] [trace] invoked: AjaxBehaviorPage.onSecurityCheck() : true
+[Click] [trace] invoked: AjaxBehaviorPage.onInit()
+[Click] [trace] invoked: 'link' ActionLink.onInit()
+[Click] [trace] the following controls have been registered as potential Ajax targets:
+[Click] [trace] ActionLink: name='link'
+[Click] [trace] invoked: 'link' ActionLink.isAjaxTarget() : true (target Ajax control found)
+[Click] [trace] invoked: 'link' ActionLink.onProcess() : true
+[Click] [trace] <token>processing Behaviors for control: 'link' ActionLink</token>
+[Click] [trace] invoked: AjaxBehaviorPage.1.<symbol>isRequestTarget()</symbol> : <varname>false</varname>
+[Click] [trace] <symbol>*no*</symbol> target behavior found for <varname>'link' ActionLink</varname> - invoking Behavior.isRequestTarget() returned false for all behaviors
+[Click] [trace] invoked: 'link' ActionLink.onDestroy()
+[Click] [trace] invoked: AjaxBehaviorPage.onDestroy()
+[Click] [info ] handleRequest: /ajax/ajax-behavior.htm - 80 ms
+ </literallayout>
+
+ <para>We can see from the log that the Ajax request sent the parameters,
+ <varname>link-id=1</varname> and <varname>actionLink=link</varname> to the server.
+ </para>
+
+ <para>Next we notice that the Behavior <symbol>isRequestTarget()</symbol>
+ returned <varname>false</varname>.
+ </para>
+
+ <para>Finally we see that <symbol>*no*</symbol> target behavior was found
+ for the <literal>Ajax target control</literal> <varname>'link' ActionLink</varname>.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="ajax-page-action" remap="h2">
+ <title>Ajax Page Action</title>
+
+ <para>Page Actions are page methods that can be invoked directly from the
+ browser. So instead of handling the Ajax request with a Control, the request
+ is handled with a page method. Like Behaviors, page methods returns an
+ ActionResult containing the Ajax data rendered to the browser.
+ </para>
+
+ <para>Page Actions have already been covered earlier. Please click
+ <link linkend="page-actions">here</link> for a detailed discussion.
+ </para>
+
+ <para>Using a Page Action for handling an Ajax request is no different from
+ a normal HTTP request. To invoke a Page Action, specify the parameter
+ <varname>"pageAction"</varname> and the name of the page method eg:
+ <symbol>"onLinkClicked"</symbol>.
+ </para>
+
+ <para>Here is an example using the
+ <ulink url="http://www.jquery.com">jQuery</ulink> JavaScript library to make
+ an Ajax request to a Page Action:
+ </para>
+
+<programlisting language="javascript">jQuery('#some-link-id').click(function() {
+
+ // The page url
+ var url = '$context/view-customers.htm';
+
+ // Specify the pageAction parameter and page method to invoke: 'onLinkClicked'
+ var extraData = 'pageAction=<symbol>onLinkClicked</symbol>';
+
+ // Perform the Ajax request
+ jQuery.get(url, extraData, function(response) {
+
+ // Update the target element with the server response
+ jQuery("#target").html("<p>" + response + "</p>");
+ });
+
+}); </programlisting>
+
+ <para>The JavaScript snippet above will send a request to the
+ <classname>ViewCustomerPage</classname> method <symbol>"onLinkClicked"</symbol>,
+ which returns an <token>ActionResult</token> instance:
+ </para>
+
+ <programlisting language="java">public class ViewCustomerPage extends Page {
+
+ ...
+
+ public <token>ActionResult</token> <symbol>onLinkClicked()</symbol> {
+ // Formatted date instance that will be returned to the browser
+ String now = format.currentDate("MMM, yyyy dd HH:MM:ss");
+
+ String msg = "PageAction method <tt>onLinkClicked()</tt> invoked at: " + now;
+
+ // Return an action result containing the message
+ return new <token>ActionResult</token>(msg, ActionResult.HTML);
+ }
+} </programlisting>
+
+ <para>The <token>ActionResult</token> contains the data that is rendered to the
+ client browser. In the example above, the action result is an HTML snippet with
+ today's date.
+ </para>
+
+ </sect1>
+
+ <sect1 id="ajax-response-types" remap="h2">
+ <title>Ajax Response Types</title>
+
+ <para>The most common server response types are:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>HTML</para>
+ </listitem>
+ <listitem>
+ <para>XML</para>
+ </listitem>
+ <listitem>
+ <para>JSON</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Click Controls render themselves as XHTML markup so can be used in
+ either XML or HTML responses.
+ </para>
+
+ <para>Here is an example showing how to return different types of responses:</para>
+
+ <programlisting language="java">public class ViewCustomerPage extends Page {
+
+ ...
+
+ public void onInit() {
+ Behavior htmlBehavior = new AjaxBehavior() {
+ public ActionResult onAction() {
+ String html = "<h1>Hello world</h1>";
+
+ // Return an HTML snippet
+ return new ActionResult(html, ActionResult.HTML);
+ }
+ };
+ htmlLink.addBehavior(htmlBehavior);
+
+ ...
+
+ Behavior xmlBehavior = new AjaxBehavior() {
+ public ActionResult onAction() {
+ String xml = "<payload>Hello world</payload>";
+
+ // Return an XML snippet
+ return new ActionResult(xml, ActionResult.XML);
+ }
+ };
+ xmlLink.addBehavior(xmlBehavior);
+
+ ...
+
+ Behavior jsonBehavior = new AjaxBehavior() {
+ public ActionResult onAction() {
+ String json = "{\"value\": \"Hello world\"}";
+
+ // Return an JSON snippet
+ return new ActionResult(json, ActionResult.JSON);
+ }
+ };
+ jsonLink.addBehavior(jsonBehavior);
+ }
+} </programlisting>
+
+ </sect1>
+
+ <sect1 id="ajax-error-handling" remap="h2">
+ <title>Ajax Error Handling</title>
+
+ <para>If an exception occurs while processing an Ajax request and the application
+ is in <literal>development</literal> mode, the exception
+ <literal>stackTrace</literal> is returned to the browser.
+ </para>
+ <para>If an exception occurs while processing an Ajax request and the application
+ is in <literal>production</literal> mode, a simple error message is returned.
+ </para>
+
+ </sect1>
+</chapter>
Modified: click/trunk/click/documentation/xdocs/src/docbook/click/click-book.xml
URL: http://svn.apache.org/viewvc/click/trunk/click/documentation/xdocs/src/docbook/click/click-book.xml?rev=991917&r1=991916&r2=991917&view=diff
==============================================================================
--- click/trunk/click/documentation/xdocs/src/docbook/click/click-book.xml (original)
+++ click/trunk/click/documentation/xdocs/src/docbook/click/click-book.xml Thu Sep 2 12:37:24 2010
@@ -4,6 +4,7 @@
<!ENTITY chapter-introduction SYSTEM "chapter-introduction.xml" >
<!ENTITY chapter-pages SYSTEM "chapter-pages.xml" >
<!ENTITY chapter-controls SYSTEM "chapter-controls.xml" >
+ <!ENTITY chapter-ajax SYSTEM "chapter-ajax.xml" >
<!ENTITY chapter-configuration SYSTEM "chapter-configuration.xml" >
<!ENTITY chapter-best-practices SYSTEM "chapter-best-practices.xml" >
]>
@@ -55,6 +56,7 @@
&chapter-introduction;
&chapter-pages;
&chapter-controls;
+ &chapter-ajax;
&chapter-configuration;
&chapter-best-practices;
Added: click/trunk/click/documentation/xdocs/src/images/ajax/ajax-class-diagram.png
URL: http://svn.apache.org/viewvc/click/trunk/click/documentation/xdocs/src/images/ajax/ajax-class-diagram.png?rev=991917&view=auto
==============================================================================
Binary file - no diff available.
Propchange: click/trunk/click/documentation/xdocs/src/images/ajax/ajax-class-diagram.png
------------------------------------------------------------------------------
svn:mime-type = image/png
Added: click/trunk/click/documentation/xdocs/src/images/ajax/ajax-request-sequence-diagram.png
URL: http://svn.apache.org/viewvc/click/trunk/click/documentation/xdocs/src/images/ajax/ajax-request-sequence-diagram.png?rev=991917&view=auto
==============================================================================
Binary file - no diff available.
Propchange: click/trunk/click/documentation/xdocs/src/images/ajax/ajax-request-sequence-diagram.png
------------------------------------------------------------------------------
svn:mime-type = image/png