| <?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. This is easier than it sounds though as there is a wide |
| range of free JavaScript libraries and plugins available to help develop |
| rich HTML front-ends. Since Click is a stateless framework and Page URLs |
| are bookmarkable, it is easy to integrate Click with existing JavaScript |
| technologies such as: |
| |
| <ulink url="http://www.jquery.com">jQuery</ulink>, |
| <ulink url="http://www.prototypejs.org/">Prototype</ulink> and |
| <ulink url="http://mootools.net/">MooTools</ulink> to name a few. |
| </para> |
| |
| <para>It is also possible to write custom |
| <ulink url="../../click-api/org/apache/click/ajax/AjaxBehavior.html">AjaxBehaviors</ulink> |
| (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 AjaxBehaviors to |
| streamline and encapsulate your client-side code. |
| </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-behavior">AjaxBehavior</link> - AjaxBehavior |
| is a specialized |
| <ulink url="../../click-api/org/apache/click/Behavior.html">Behavior</ulink> |
| that enables Controls to handle and respond to Ajax requests |
| </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 |
| simple way to handle and respond to Ajax requests |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| </sect1> |
| |
| <sect1 id="ajax-behavior" remap="h2"> |
| <title>AjaxBehavior</title> |
| |
| <para><ulink url="ajax-behavior">AjaxBehavior</ulink> is an interface that |
| extends Behavior (covered <link linkend="behavior">earlier</link>) and |
| adds the ability to handle and process incoming Ajax requests. |
| </para> |
| |
| <para>Click also provides a default AjaxBehavior implementation, |
| <ulink url="../../click-api/org/apache/click/ajax/DefaultAjaxBehavior.html">DefaultAjaxBehavior</ulink>. |
| Using this class you only need to implement the methods you are interested in. |
| </para> |
| |
| |
| <para>AjaxBehaviors, like Behaviors, are added to controls |
| through the <ulink url="../../click-api/org/apache/click/control/AbstractControl.html#addBehavior(org.apache.click.Behavior)">AbstractControl.addBehavior()</ulink> |
| method. |
| </para> |
| |
| <para>AjaxBehaviors provides an |
| <ulink url="../../click-api/org/apache/click/ajax/AjaxBehavior.html#onAction(org.apache.click.Control)">onAction</ulink> |
| method (similar to <classname>ActionListener</classname>) that is invoked to |
| handle Ajax requests. The <methodname>onAction</methodname> |
| method returns an <ulink url="../../click-api/org/apache/click/ActionResult.html">ActionResult</ulink> |
| containing the data to be rendered to the browser. |
| </para> |
| |
| <para>The <classname>Control</classname>, <classname>Behavior</classname>, |
| <classname>AjaxBehavior</classname> and <classname>ActionResult</classname> |
| classes are 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 following method is exposed by Control in order to handle Ajax |
| requests: |
| </para> |
| |
| <itemizedlist> |
| <listitem> |
| <para> |
| <ulink url="../../click-api/org/apache/click/Control.html#isAjaxTarget(org.apache.click.Context)">isAjaxTarget(Context)</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. Other |
| controls won't be processed. 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, which is then passed as an Ajax request parameter to the server. |
| More on this later. |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The Behavior interface has been covered <link linkend="behavior-class-diagram">already</link> |
| so we'll look at AjaxBehavior next: |
| </para> |
| |
| <itemizedlist> |
| <listitem> |
| <para> |
| <ulink url="../../click-api/org/apache/click/Behavior.html#isAjaxTarget(org.apache.click.Context)">isAjaxTarget(Context)</ulink> |
| - determines whether the AjaxBehavior is the request target or not. Click |
| will only invoke the AjaxBehavior <methodname>onAction</methodname> method |
| if <methodname>isAjaxTarget</methodname> returns true. This |
| allows for fine grained control over the execution of the <methodname>onAction</methodname> |
| method. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <ulink url="../../click-api/org/apache/click/ajax/AjaxBehavior.html#onAction(org.apache.click.Control)">onAction(Control)</ulink> |
| - the AjaxBehavior action method for handling Ajax requests. |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| <para>The <methodname>onAction</methodname> method returns an |
| <classname>ActionResult</classname> instance, containing the data to be |
| rendered to the browser. ActionResult can return any type of response: String, |
| byte array or a Velocity (Freemarker) template. |
| </para> |
| |
| <para>The <methodname>isAjaxTarget</methodname> method controls whether or |
| not the <methodname>onAction</methodname> method should be invoked. |
| <methodname>isAjaxTarget()</methodname> is typically used to target the |
| AjaxBehavior for specific JavaScript events. For example an AjaxBehavior might |
| only handle <literal>click</literal> or <literal>blur</literal> JavaScript events. |
| Of course the client-side code initiating the Ajax request should pass |
| the JavaScript event to the server. |
| </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#setContentType(java.lang.String)">setContentType(String)</ulink> |
| - set the ActionResult content type, for example: <literal>text/html</literal>, |
| <literal>text/xml</literal>, <literal>application/json</literal> etc. |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| </sect1> |
| |
| <sect1 id="ajax-behavior-execution" remap="h2"> |
| <title>AjaxBehavior Execution</title> |
| |
| <para>The execution sequence for an <classname>AjaxBehavior</classname> |
| being processed and rendered is illustrated in the figure below. 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 and that only the |
| <literal>Ajax target Control</literal> is processed. |
| </para> |
| |
| <figure id="ajax-behavior-sequence-diagram"> |
| <title>AjaxBehavior 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 |
| <ulink url="../../click-api/org/apache/click/ControlRegistry.html">ControlRegistry</ulink> |
| as a potential |
| <ulink url="../../click-api/org/apache/click/ControlRegistry.html#registerAjaxTarget(org.apache.click.Control)">Ajax target control</ulink>. |
| </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 Controls |
| registered with the ControlsRegistry and invokes each Control's |
| <methodname>isAjaxTarget</methodname> method. The first control which |
| <methodname>isAjaxTarget</methodname> method returns <emphasis>true</emphasis>, |
| will be the Ajax target. |
| </para> |
| |
| <para>The simplest <methodname>isAjaxTarget</methodname> implementation is |
| to return <emphasis>true</emphasis> if the Control ID is passed as a request |
| parameter. The client-side JavaScript code that initiate the Ajax request, |
| must 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. |
| </para> |
| |
| <para> |
| <emphasis role="bold">Please note:</emphasis> since Click is a stateless framework, |
| 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 include 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. |
| Putting it another way, if for example an ActionLink is clicked and |
| we only pass the link's HTML ID parameter, Click will identify the link |
| as the Ajax target control and invoke the link's |
| <methodname>onProcess</methodname> method. The |
| <methodname>onProcess</methodname> method is where the link's values are |
| bound and if it was clicked it's action event (AjaxBehavior) will be fired. |
| An ActionLink is "clicked" if the <literal>actionLink</literal> parameter |
| has a value matching the link's name. If no <literal>actionLink</literal> |
| parameter is present, the server doesn't know that the link was clicked |
| and won't fire the AjaxBehavior's <methodname>onAction</methodname> event. |
| So for an Ajax request it is still necessary to pass all the parameters |
| normally expected by the ActionLink <methodname>onProcess</methodname> method. |
| For ActionLink that means the Ajax request must include it's |
| <literal>href</literal> parameters while a Form would require all it's |
| Field <literal>name/value</literal> pairs. |
| </para> |
| |
| <para>Next, the target control <classname>AjaxBehaviors</classname> are |
| fired. The ClickServlet iterates over the control AjaxBehaviors and for each |
| AjaxBehavior invoke the method: <methodname>isAjaxTarget</methodname>. |
| Each AjaxBehavior which <methodname>isAjaxTarget</methodname> method returns |
| <emphasis>true</emphasis>, will have their <methodname>onAction</methodname> |
| method invoked to handle the Ajax request. The AjaxBehavior's |
| <methodname>onAction</methodname> method returns an |
| <classname>ActionResult</classname> that is rendered to the browser. |
| </para> |
| |
| <para>Please note: multiple AjaxBehaviors can handle the same Ajax request, |
| however only the first <classname>ActionResult</classname> returned will be |
| rendered to the browser. If an <methodname>onAction</methodname> method |
| returns <literal>null</literal>, the <classname>ActionResult</classname> |
| returned by the next AjaxBehavior's 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 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 a |
| <symbol>DefaultAjaxBehavior</symbol>. DefaultAjaxBehavior is the default |
| implementation of the <classname>AjaxBehavior</classname> interface. Below is |
| the Page class, <classname>AjaxBehaviorPage.java</classname>, showing a |
| <symbol>DefaultAjaxBehavior</symbol> added to an ActionLink, called |
| <emphasis>link</emphasis> with an HTML ID of <varname>link-id</varname>. |
| The <symbol>DefaultAjaxBehavior</symbol> <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 a DefaultAjaxBehavior to the link. The DefaultAjaxBehavior will be invoked when the |
| // link is clicked. |
| link.addBehavior(new <symbol>DefaultAjaxBehavior()</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 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 the <symbol>DefaultAjaxBehavior</symbol> to the ActionLink. |
| Adding a Behavior to a control will also register that control with the |
| <ulink url="../../click-api/org/apache/click/ControlRegistry.html">ControlRegistry</ulink> |
| 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 <symbol>DefaultAjaxBehavior</symbol> |
| <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>Finally we return an <token>ActionResult</token> containing some |
| HTML content that is rendered to the browser. |
| </para> |
| </callout> |
| </calloutlist> |
| |
| <para>Below we show the Page template <literal>ajax-behavior.htm</literal>, |
| containing the client-side JavaScript code that will initiate the Ajax request. |
| </para> |
| |
| <para><emphasis role="bold">Note:</emphasis> the example below uses the |
| <ulink url="http://www.jquery.com">jQuery</ulink> library, but any other |
| library can be used. Also see the online Click examples for more Ajax demos. |
| </para> |
| |
| <programlisting language="javascript"><!-- // $link is a Velocity reference that will render an ActionLink at runtime. --> |
| Click $link to make an Ajax request to the server. |
| |
| <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 by the server |
| |
| // Find the div element 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 results in a more responsive UI. |
| </para> |
| </callout> |
| <callout arearefs="co-ajax-link-id" id="ca-ajax-link-id"> |
| <para>This is an important step. We need to pass the link's <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 doesn't actually use the <literal>value</literal> of the |
| parameter, it is enough that the <literal>name</literal> is present. |
| In this example we pass a value of <varname>1</varname>, but any |
| other value could be used, or even left out. |
| </para> |
| </callout> |
| <callout arearefs="co-ajax-jq-href" id="ca-ajax-jq-href"> |
| <para>This is another important step. In addition to the ActionLink HTML ID |
| pararameter, we also need to send the link's <varname>href</varname> |
| parameters, otherwise the ActionLink <methodname>onProcess</methodname> |
| method won't fire the <classname>AjaxBehavior</classname> |
| <methodname>onAction</methodname> event. An easy way to achieve this to |
| set the Ajax <varname>URL</varname> to the ActionLink |
| <varname>href</varname> value. |
| </para> |
| </callout> |
| <callout arearefs="co-ajax-jq-response" id="ca-ajax-jq-response"> |
| <para>Finally we the jQuery |
| <ulink url="http://api.jquery.com/html/#html2">html</ulink> function |
| to update the <emphasis>div</emphasis> content with the server response. |
| </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> (Ajax target control found) |
| [Click] [trace] invoked: 'link' ActionLink.<symbol>onProcess()</symbol> : <varname>true</varname> |
| [Click] [trace] <token>processing AjaxBehaviors 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) - 1 ms |
| [Click] [trace] invoked: 'link' ActionLink.onDestroy() |
| [Click] [trace] invoked: AjaxBehaviorPage.onDestroy() |
| [Click] [info ] handleRequest: /ajax/ajax-behavior.htm - 25 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 passed 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 an AjaxBehavior 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 used 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 AjaxBehavior</literal> |
| by invoking the AjaxBehavior#<symbol>isRequestTarget</symbol> method, which |
| returned <varname>true</varname>. |
| </para> |
| |
| <para>The AjaxBehavior#<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 this can occur 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 problem is |
| if no Control is registered ith the <classname>ControlRegistry</classname>, |
| thus there is no potential <literal>Ajax target control</literal>. This can |
| occur if no Behavior is 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 request parameters sent is |
| <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 an AjaxBehavior to the |
| ActionLink so the ActionLink is registered as an Ajax target. |
| </para> |
| |
| <para>Finally, we see that <symbol>*no*</symbol> Ajax target control was found. |
| This is because the ActionLink ID attribute, <varname>link-id</varname>, |
| does not match the incoming request parameter, <varname>actionLink=link</varname>, |
| 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-ajax-behavior" remap="h3"> |
| <title>Ajax Trace Log - No Target AjaxBehavior Found</title> |
| |
| <para>Below we show a log trace where no <literal>target AjaxBehavior</literal> |
| is found. This can occur if no <classname>AjaxBehavior's</classname> |
| <symbol>isRequestTarget</symbol> returns true. |
| </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 (Ajax target control found) |
| [Click] [trace] invoked: 'link' ActionLink.onProcess() : true |
| [Click] [trace] <token>processing AjaxBehaviors for control: 'link' ActionLink</token> |
| [Click] [trace] invoked: AjaxBehaviorPage.1.<symbol>isRequestTarget()</symbol> : <varname>false</varname> |
| [Click] [trace] <symbol>*no*</symbol> target AjaxBehavior found for <varname>'link' ActionLink</varname> - invoking AjaxBehavior.isRequestTarget() returned false for all AjaxBehaviors |
| [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 AjaxBehavior <symbol>isRequestTarget()</symbol> |
| returned <varname>false</varname>. |
| </para> |
| |
| <para>Finally we see that <symbol>*no*</symbol> target AjaxBehavior 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 <emphasis>page methods</emphasis> that can be invoked |
| directly from the browser. So instead of handling the Ajax request with a |
| Control, the request is handled with a <emphasis>page method</emphasis>. |
| </para> |
| |
| <para>Similar to the AjaxBehavior <methodname>onAction</methodname> method, |
| <emphasis>page methods</emphasis> returns an <classname>ActionResult</classname> |
| containing the data to render to the browser. |
| </para> |
| |
| <para>Page Actions have been covered earlier. Please click |
| <link linkend="page-actions">here</link> for a detailed overview. |
| </para> |
| |
| <para>Using a Page Action for handling an Ajax request is no different from |
| the normal HTTP version. 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 ViewCustomerPage 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 |
| containing todays 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 HelloWorldPage extends Page { |
| |
| ... |
| |
| public void onInit() { |
| Behavior htmlBehavior = new DefaultAjaxBehavior() { |
| 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 DefaultAjaxBehavior() { |
| 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 DefaultAjaxBehavior() { |
| 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> |