What is it?

AjaxAnywhere (reloaded) is an Open Source declarative Ajax framework for the JVM. It enables the developer to provide async server side rendering and page refresh without Javascript coding.

This library is a fork of the ancient and abandoned AjaxAnywhere library hosted in SourceForge to add new features like:

  • Declarative programming style via HTML5 custom elements markup.

  • The developer does not need to write any Javascript code. You just need to include the AjaxAnywhere Javascript file in your page and it will do the rest for you!!

  • AjaxAnywhere client side javascript code now relies on jQuery to implement all the required features.

  • Code base refactored aiming for simplification and speed.

  • There are no external Java dependencies.

  • HTML parsing implementation does not rely on the Java SE HTML anymore. In fact no HTML parser is used now. Just plain old String.substring method is used.

  • JSF support has been dropped, because a similar but more cumbersome idea is already built-in within the JSF spec since version 2.0.

AjaxAnywhere continues to be a PAGE or PAGE FRAGMENT oriented framework and not a component framework. So don’t expect to find "yet another autocomplete component".

You can see didactic working EXAMPLES HERE.

How does it work?

The idea is really simple:

  1. Mark the zones to refresh in you JSP template.

  2. Add special aa-refresh-zones on all action trigger elements that you want to "ajaxify" like: forms, submit buttons, input images or even normal links.

  3. You can develop your server code as if you were implementing the classic "synchronous" approach.

  4. AjaxAnywhere servlet filter will intercept the Ajax request and extract the content that needs to be refreshed from the response. The "refresh zones" contents will be put in XML back to the client

  5. AjaxAnywhere Javascript is responsible for parsing the XML and inserting the content in the page.

The following picture and diagram may help to visualize it:

Figure 1 - "Ajaxified" form with AjaxAnywhere
AjaxAnywhere request life cycle
Figure 2 - AjaxAnywhere request life cycle

Usage

Installation

  • Add the AjaxAnywhere library dependency:

<dependency>
  <groupId>com.nerderg.ajaxanywhere</groupId>
  <artifactId>ajaxanywhere</artifactId>
  <version>2.1.1</version>
</dependency>
  • Register the AjaxAnywhere filter in your web.xml: it is important to register this filter before any other filter that is likely to modify the response content (e.g Sitemesh, …):

<filter>
    <filter-name>AjaxAnywhere</filter-name>
    <filter-class>com.nerderg.ajaxanywhere.AAFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>AjaxAnywhere</filter-name>
    <servlet-name>MyServlet</servlet-name>
</filter-mapping>
  • Import jQuery (1.7+) and AjaxAnywhere Javascript libraries (example):

<script src="<c:url value="/webjars/jquery/1.11.2/jquery.min.js"/>"></script>
<script src="<c:url value="/webjars/ajaxanywhere/2.1/aa.js"/>"></script>
  • You can also add a javascript dependency with the AjaxQ library to enable the queueing features (example):

<script src="<c:url value="/webjars/AjaxQ/0.0.2/ajaxq.js"/>"></script>
Queueing feature only available since version 2.1
  • If you are using a noncompliant Servlet 3.x Application Server (like Tomcat 6.x), then you need to register the "Webjars servlet 2.x add-on".

This is due to the fact that AjaxAnywhere is using the Servlet 3.0 mechanism to serve static resources from within a JAR file following the WebJars convention:

How to declare AjaxAnywhere triggers

These elements will trigger the partial page refresh when clicked. AjaxAnywhere defines the following HTML5 custom attributes to declare any "clickable" element as an AjaxAnywhere trigger:

Attribute AA Version Mandatory Mission

aa-refresh-zones

2.0

yes

comma separated list with names of the "zones" you want to refresh.

aa-method

2.1

no

HTTP method: GET, POST, …​ Form elements default this value to the form method attribute. For links the default is GET.

aa-js-before

2.1

no

javascript that will get evaluated before performing the ajax request. Eg: aa-js-before="loadDynamicaParams();"

aa-js-after

2.1

no

javascript that will get evaluated after performing the ajax request. Eg: aa-js-before="openModalDialog();"

aa-queue

2.1

no

AjaxQ lib is required for this feature. You would use it if multiple ajax requests have to be performed sequentially for the page refresh to be coherent.

These are the three possible values:

  • true: to queue ajax request.

  • abort: aborts previous ongoing request, and removes any unprocessed requests from the queue.

  • clear: removes any unprocessed requests from the queue but lets finish previous ongoing request.

aa-href

2.1

no

contains the url to get the relevant content for those elements that unlike the form or links have no standard means to specify a url

Next are the most common trigger examples which are usually associated with the form, input, button,select or link/anchor elements:

  • <form … >: this will automatically "ajaxify" all the submits from within the form (working example):

<form action="${action}" method="post" aa-refresh-zones="aaZone1Example1, aaZone2Example1">
...
</form>
  • <input type="submit" … >, <input type="image" … >, <button type="submit" … >: this way you can specify more fine grained behavior refresh zones depending upon the clicked button within a form. (working example):

<form action="${action}" method="post">
...
  <div>
    <button type="submit" aa-refresh-zones="aaZone1Example2" class="btn btn-primary" name="refreshTextButton" value="Refresh Text">Refresh Text</button>
    <input type="image" aa-refresh-zones="aaZone1Example2" src="<c:url value='/img/refresh.png'/>" name="refreshTextButton" value="Refresh Text"/>
    <input type="submit" aa-refresh-zones="aaZone2Example2" class="btn btn-info" name="showCodeButton" value="Show Code"/>
  </div>
</form>
The refresh zones specified in a submit element will always override those specified in the form
  • <select … >: you can also trigger an Ajax request when the selected value in a drop-down list changes: (working example):

<form action="${action}" method="post">
...
  <sf:select path="continentCode" aa-refresh-zones="countryZone, capitalZone" id="continentCode">
      <sf:option value="">-- Select One --</sf:option>
      <sf:options items="${countryForm.continentsSet}" itemLabel="value" itemValue="key"/>
  </sf:select>
...
</form>
  • <a href="/url" … >: without requiring a form scope, you can also "ajaxify" any link within your page (working example):

<a href="<c:url value='/action/examples/4?data=whatever'/>" aa-refresh-zones="codeLayer4">Show Code</a>

Mark the 'refresh zones' in your page

It is as simple as:

  • declaring the AjaxAnywhere taglib in your JSP template:

<%@ taglib uri="http://com.nerderg/ajaxanywhere" prefix="aa" %>
  • and embed the content you want to refresh within the AjaxAnywhere tag <aa:zone id="someid"/>:

<aa:zone id="myZone">
  <!-- Zone Content -->
  ...
</aa:zone>

By default this will generate a <div/> with some special markup:

<div style="display:inline;" id="myZone">

<!-- @end of zone [myZone]@ --></div>

New 'refresh zones' features explained

Since version 2.1 a few new use cases have been added to the way refresh zones are handled. To achieve this we have added a few more attributes to the <aa:zone/> taglib.

1. Everything can be a "refresh zone"

As explained previously, a refresh zone is encapsulated within a <div/>. That means the refresing zones were limited to be declared outside first level block elements (eg: <div/> or <table/>), but not other nested or inline elements like a <tbody/> or <tr/>. Now using the attribute tag we can specify what HTML5 element should be rendered.

So given this template:

<table>
<aa:zone id="tbodyZone" tag="tbody"> (1)
  <tr>
  ...
  </tr>
  ...
</aa:zone>
...
</table>
1 Check tag attribute in the table bellow

the following will be rendered:

<table>
<tbody id="tbodyZone">
  <tr>
  ...
  </tr>
  ...
<!-- @end of zone [tbodyZone]@ --></tbody>
...
</table>
When using the tag attribute the refreshed content will replace the declared zone unlike the default behaviour which would append the content to the generated <div/> container. See $.html() vs $.replaceWith()

2. Auto refresh zone at page loading time

For those times where you want to defer the loading of a particular fragment to once the parent page is loaded, we provide the attribute href. There you can specify the location of the content you want to include.

<aa:zone id="deferredLoadingZone" href="/some-url"> (1)
</aa:zone>
1 Check href attribute in the table bellow

Taglib <aa:zone /> attributes

Name AA Version Mandatory Description

id

2.0

Yes

Unique identifier for the refresh zone within the page.

tag

2.1

No

Html5 inline or block element tag to be generated instead of the default '<div/>' block tag

href

2.1

No

URL with the content that will get refresh at page load time.

jsBefore

2.1

No

javascript that will get evaluated before performing the ajax request.

jsAfter

2.1

No

javascript that will get evaluated after performing the ajax request.

jsBefore and jsAfter attributes are only evaluated if href has been used.

Grails plugin

We have developed a Grails plugin that makes using AjaxAnywhere even easier and more straight forward.

Installation

Add the plugin dependency in your BuildConfig.groovy file:

compile ":ajaxanywhere:1.0"

That’s it! It is quite simple compared to the general installation process that we described previously, isn’t it?. That’s the beauty of Grails plugins…​one of them anyway.

Usage

Apart from the fact that you don’t need to declare the tag library, you can refer to the general Usage section above. You also need to take into consideration the following guidelines depending on the layout manager you are using.

For the Resources Plugin

If you are using the Resources Plugin, you will need import the ajaxanywhere resources module either in your resources file:

modules = {
...
  myModule {
    dependsOn 'ajaxanywhere'

  }
...
}

or in the page you are planning to use it:

<r:require modules="ajaxanywhere"/>
There is a limitation with the Resources Plugin that makes impossible to perform a full page refresh, so the development will have to be oriented to refresh page fragments, which is what you do most of the time anyway.
At the time of writing I was using the Resources plugin version 1.2.14

For Assets Pipeline Plugin

If you using the Assets Pipeline Plugin → TODO

Version compatibility

AA Grails plugin version AA Version Grails version

1.0

2.1.1

1.3.x to 2.x

F.A.Q.

Where can I download the library?

We highly recommend that you use a dependency manager like Maven, Gradle or Apache Ivy and use the Maven coordinates explained above. But if you are stuck in an awful legacy project and you want to make it look nicer with AjaxAnywhere, then you can download the library from the AjaxAnywhere Maven repository hosted by Sonatype.

How can I display a spinner or any other notification mechanism while the Ajax request is processed?

Since AjaxAnywhere delegates on jQuery to perform the Ajax request, you just need to register an event handler using the $.ajaxStart() method and implement the behavior you want. Next there is an example that shows how to do it:

var x,y;

$(function () {
  $('body').mousemove(function (e) {
    x = e.pageX;
    y = e.pageY;
  });

  $(document).ajaxStart(
    function (e) {
      $('#spinner').css('left', x);
      $('#spinner').css('top', y).show();
      $('body').css('cursor', 'wait');
    }).ajaxComplete(function () {
      $('#spinner').hide();
      $('body').css('cursor', 'auto');
    });
});

Is there any way to identify an AjaxAnywhere Ajax request at server side?

Sure you can! In fact one very common use case in a controller is to perform either a forward or a redirect depending on if it was an Ajax request or not. AjaxAnywhere provides the static AAUtils.isAjaxAnywhereRequest(request) method for your convenience:

...
if (AAUtils.isAjaxAnywhereRequest(request) {
  // Perform request forward
} else {
  // Perform response redirect
}

What are the advantages of using AjaxAnywhere?

The advantages are those that come from using a declarative style of programming. By reducing the amount of boiler plate code and homogenizing your code, you instantly improve on these parameters that define how good your code is: reliability, simplicity, productivity and maintainability. For most of the use cases that a developer can face, AjaxAnywhere is the easiest and most cost-effective way to implement Ajax enabled web applications.

You can also implement AjaxAnywhere in your legacy projects without making any change to your controller layer. It also makes it easier to implement graceful degradation or continued enhancement to your UI so you can meet you accessibility requirements without crippling the UX.

Are there any inconveniences?

Although AjaxAnywhere impact on response time is negligible for the vast majority of use cases that we all developers have to deal with on daily basis, but there could be certain scenarios where 10ms per request must be taken into consideration.

I am still stuck in JDK 1.4, can I still use AjaxAnywhere?

We feel so sorry for you mate… what can we do? Oh yeah! we created a profile in the AjaxAnywhere library pom file so you can download the source code, and package your own JDK 1.4 compatible JAR. Once you pull the code, execute the following Maven command in the AjaxAnywhere Core folder (not the parent project folder):

mvn package -P1.4

What external dependencies does AjaxAnywhere have?

None whatsoever. You just need a JRE 5+ and a Servlet 2.3+ container. The application logging is performed with JUL (Java Util Logging).

At client side though you will need jQuery 1.7+, but jQuery 1.9.x or greater is recommended.

What if I want to bridge the JUL based traces to SLF4J?

AjaxAnywhere includes a ServletContextListener implementation to do that. Just add it to your web.xml as follows:

<!-- Jul to Slf4j Bridge Listener -->
<listener>
    <listener-class>
        com.nerderg.ajaxanywhere.listener.JulToSlf4jBridgeListener
    </listener-class>
</listener>

Changelog

  • version 2.1.1 (07/05/2015):

    • Added support for new uses cases by adding more custom HTML5 attributes for AA triggers

    • Added new attributes to the taglib

    • Now any HTML5 element can be a "refreshable" zone.

    • Updated documentation using Asciidoc.

    • Added support for declarative queueing of the Ajax requests.

    • Other minor improvements and bug fixes.

  • version 2.1 (07/05/2015):

    • Bogus release due to versioning mistake. Please skip

  • version 2.0 (13/03/2013):

    • Initital Release