228 lines
14 KiB
XML
228 lines
14 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<chapter id="spring-js">
|
|
<title>Spring JavaScript Quick Reference</title>
|
|
<sect1 id="spring-js-introduction">
|
|
<title>Introduction</title>
|
|
<para>
|
|
Spring Javascript (spring-js) is a lightweight abstraction over common JavaScript toolkits such as Dojo.
|
|
It aims to provide a common client-side programming model for progressively enhancing a web page with rich widget behavior and Ajax remoting.
|
|
</para>
|
|
<para>
|
|
Use of the Spring JS API is demonstrated in the the Spring MVC + Web Flow version of the Spring Travel reference application.
|
|
In addition, the JSF components provided as part of the Spring Faces library build on Spring.js.
|
|
</para>
|
|
</sect1>
|
|
<sect1 id="spring-js-resource-servlet">
|
|
<title>Serving Javascript Resources</title>
|
|
<para>
|
|
Spring JS provides a generic <code>ResourceServlet</code> to serve web resources such as JavaScript and CSS files from jar files, as well as the webapp root directory.
|
|
This servlet provides a convenient way to serve Spring.js files to your pages.
|
|
To deploy this servlet, declare the following in <code>web.xml</code>:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<!-- Serves static resource content from .jar files such as spring-js.jar -->
|
|
<servlet>
|
|
<servlet-name>Resource Servlet</servlet-name>
|
|
<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
|
|
</servlet>
|
|
|
|
<!-- Map all /resources requests to the Resource Servlet for handling -->
|
|
<servlet-mapping>
|
|
<servlet-name>Resource Servlet</servlet-name>
|
|
<url-pattern>/resources/*</url-pattern>
|
|
</servlet-mapping>]]>
|
|
</programlisting>
|
|
</sect1>
|
|
<sect1 id="spring-js-includes">
|
|
<title>Including Spring Javascript in a Page</title>
|
|
<para>
|
|
Spring JS is designed such that an implementation of its API can be built for any of the popular Javascript toolkits.
|
|
The initial implementation of Spring.js builds on the Dojo toolkit.
|
|
</para>
|
|
<para>
|
|
Using Spring Javascript in a page requires including the underlying toolkit as normal,
|
|
the <code>Spring.js</code> base interface file, and the <code>Spring-(library implementation).js</code> file for the underlying toolkit.
|
|
As an example, the following includes obtain the Dojo implementation of Spring.js using the <code>ResourceServlet</code>:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js" />"> </script>
|
|
<script type="text/javascript" src="<c:url value="/resources/spring/Spring.js" />"> </script>
|
|
<script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js" />"> </script>]]>
|
|
</programlisting>
|
|
<para>
|
|
When using the widget system of an underlying library, typically you must also include some CSS resources to obtain the desired look and feel.
|
|
For the booking-mvc reference application, Dojo's <code>tundra.css</code> is included:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<link type="text/css" rel="stylesheet" href="<c:url value="/resources/dijit/themes/tundra/tundra.css" />" />]]>
|
|
</programlisting>
|
|
</sect1>
|
|
<sect1 id="spring-js-decorations">
|
|
<title>Spring Javascript Decorations</title>
|
|
<para>
|
|
A central concept in Spring Javascript is the notion of applying decorations to existing DOM nodes.
|
|
This technique is used to progressively enhance a web page such that the page will still be functional in a less capable browser.
|
|
The <code>addDecoration</code> method is used to apply decorations.
|
|
</para>
|
|
<para>
|
|
The following example illustrates enhancing a Spring MVC <code><form:input></code> tag with rich suggestion behavior:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<form:input id="searchString" path="searchString"/>
|
|
<script type="text/javascript">
|
|
Spring.addDecoration(new Spring.ElementDecoration({
|
|
elementId: "searchString",
|
|
widgetType: "dijit.form.ValidationTextBox",
|
|
widgetAttrs: { promptMessage : "Search hotels by name, address, city, or zip." }}));
|
|
</script>]]>
|
|
</programlisting>
|
|
<para>
|
|
The <code>ElementDecoration</code> is used to apply rich widget behavior to an existing DOM node.
|
|
This decoration type does not aim to completely hide the underlying toolkit, so the toolkit's native widget type and attributes are used directly.
|
|
This approach allows you to use a common decoration model to integrate any widget from the underlying toolkit in a consistent manner.
|
|
See the <code>booking-mvc</code> reference application for more examples of applying decorations to do things from suggestions to client-side validation.
|
|
</para>
|
|
<para>
|
|
When using the <code>ElementDecoration</code> to apply widgets that have rich validation behavior, a common need is to prevent the form from being submitted to the server until validation passes.
|
|
This can be done with the <code>ValidateAllDecoration</code>:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<input type="submit" id="proceed" name="_eventId_proceed" value="Proceed" />
|
|
<script type="text/javascript">
|
|
Spring.addDecoration(new Spring.ValidateAllDecoration({ elementId:'proceed', event:'onclick' }));
|
|
</script>]]>
|
|
</programlisting>
|
|
<para>
|
|
This decorates the "Proceed" button with a special onclick event handler that fires the client side validators and does not allow the form to submit until they pass successfully.
|
|
</para>
|
|
<para>
|
|
An <code>AjaxEventDecoration</code> applies a client-side event listener that fires a remote Ajax request to the server. It also auto-registers a callback function to link in the response:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<a id="prevLink" href="search?searchString=${criteria.searchString}&page=${criteria.page - 1}">Previous</a>
|
|
<script type="text/javascript">
|
|
Spring.addDecoration(new Spring.AjaxEventDecoration({
|
|
elementId: "prevLink",
|
|
event: "onclick",
|
|
params: { fragments: "body" }
|
|
}));
|
|
</script>]]>
|
|
</programlisting>
|
|
<para>
|
|
This decorates the onclick event of the "Previous Results" link with an Ajax call, passing along a special parameter that specifies the fragment to be re-rendered in the response.
|
|
Note that this link would still be fully functional if Javascript was unavailable in the client.
|
|
(See the section on <link linkend="spring-js-ajax">Handling Ajax Requests</link> for details on how this request is handled on the server.)
|
|
</para>
|
|
<para>
|
|
It is also possible to apply more than one decoration to an element.
|
|
The following example shows a button being decorated with Ajax and validate-all submit suppression:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<input type="submit" id="proceed" name="_eventId_proceed" value="Proceed" />
|
|
<script type="text/javascript">
|
|
Spring.addDecoration(new Spring.ValidateAllDecoration({elementId:'proceed', event:'onclick'}));
|
|
Spring.addDecoration(new Spring.AjaxEventDecoration({elementId:'proceed', event:'onclick',formId:'booking', params:{fragments:'messages'}}));
|
|
</script>]]>
|
|
</programlisting>
|
|
<para>
|
|
It is also possible to apply a decoration to multiple elements in a single statement using Dojo's query API.
|
|
The following example decorates a set of checkbox elements as Dojo Checkbox widgets:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<div id="amenities">
|
|
<form:checkbox path="amenities" value="OCEAN_VIEW" label="Ocean View" /></li>
|
|
<form:checkbox path="amenities" value="LATE_CHECKOUT" label="Late Checkout" /></li>
|
|
<form:checkbox path="amenities" value="MINIBAR" label="Minibar" /></li>
|
|
<script type="text/javascript">
|
|
dojo.query("#amenities input[type='checkbox']").forEach(function(element) {
|
|
Spring.addDecoration(new Spring.ElementDecoration({
|
|
elementId: element.id,
|
|
widgetType : "dijit.form.CheckBox",
|
|
widgetAttrs : { checked : element.checked }
|
|
}));
|
|
});
|
|
</script>
|
|
</div>]]>
|
|
</programlisting>
|
|
</sect1>
|
|
<sect1 id="spring-js-ajax">
|
|
<title>Handling Ajax Requests</title>
|
|
<para>
|
|
Spring Javascript's client-side Ajax response handling is built upon the notion of receiving "fragments" back from the server.
|
|
These fragments are just standard HTML that is meant to replace portions of the existing page.
|
|
The key piece needed on the server is a way to determine which pieces of a full response need to be pulled out for partial rendering.
|
|
</para>
|
|
<para>
|
|
In order to be able to render partial fragments of a full response, the full response must be built using a
|
|
templating technology that allows the use of composition for constructing the response, and for the member
|
|
parts of the composition to be referenced and rendered individually.
|
|
Spring Javascript provides some simple Spring MVC extensions that make use of Tiles to achieve this.
|
|
The same technique could theoretically be used with any templating system supporting composition.
|
|
</para>
|
|
<para>
|
|
Spring Javascript's Ajax remoting functionality is built upon the notion that the core handling code for an
|
|
Ajax request should not differ from a standard browser request, thus no special knowledge of an Ajax request
|
|
is needed directly in the code and the same hanlder can be used for both styles of request.
|
|
</para>
|
|
<sect2 id="custom-ajax-handler">
|
|
<title>Providing a Library-Specific AjaxHandler</title>
|
|
<para>
|
|
The key interface for integrating various Ajax libraries with the Ajax-aware behavior of Web Flow (such as not redirecting for a
|
|
partial page update) is <code>org.springframework.js.AjaxHandler</code>. A <code>SpringJavascriptAjaxHandler</code> is configured by default that is able to
|
|
detect an Ajax request submitted via the Spring JS client-side API and can respond appropriately in the case where a redirect is required. In
|
|
order to integrate a different Ajax library (be it a pure JavaScript library, or a higher-level abstraction such as an Ajax-capable JSF
|
|
component library), a custom <code>AjaxHandler</code> can be injected into the <code>FlowHandlerAdapter</code> or <code>FlowController</code>.
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="spring-js-ajax-mvc">
|
|
<title>Handling Ajax Requests with Spring MVC Controllers</title>
|
|
<para>
|
|
In order to handle Ajax requests with Spring MVC controllers, all that is needed is the configuration of
|
|
the provided Spring MVC extensions in your Spring application context for rendering the partial response
|
|
(note that these extensions require the use of Tiles for templating):
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
|
|
<property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
|
|
</bean>]]>
|
|
</programlisting>
|
|
<para>
|
|
This configures the <code>AjaxUrlBasedViewResolver</code> which in turn interprets Ajax requests and creates <code>FlowAjaxTilesView</code> objects to handle rendering of the appropriate fragments.
|
|
Note that <code>FlowAjaxTilesView</code> is capable of handling the rendering for both Web Flow and pure Spring MVC requests.
|
|
The fragments correspond to individual attributes of a Tiles view definition. For example, take the following Tiles view definition:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<definition name="hotels/index" extends="standardLayout">
|
|
<put-attribute name="body" value="index.body" />
|
|
</definition>
|
|
|
|
<definition name="index.body" template="/WEB-INF/hotels/index.jsp">
|
|
<put-attribute name="hotelSearchForm" value="/WEB-INF/hotels/hotelSearchForm.jsp" />
|
|
<put-attribute name="bookingsTable" value="/WEB-INF/hotels/bookingsTable.jsp" />
|
|
</definition>]]>
|
|
</programlisting>
|
|
<para>
|
|
An Ajax request could specify the "body", "hotelSearchForm" or "bookingsTable" to be rendered as fragments in the request.
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="spring-js-ajax-mvc-webflow">
|
|
<title>Handling Ajax Requests with Spring MVC + Spring Web Flow</title>
|
|
<para>
|
|
Spring Web Flow handles the optional rendering of fragments directly in the flow definition language through use of the <code>render</code> element.
|
|
The benefit of this approach is that the selection of fragments is completely decoupled from client-side code, such that no special parameters need to be passed with the request the way they
|
|
currently must be with the pure Spring MVC controller approach.
|
|
For example, if you wanted to render the "hotelSearchForm" fragment from the previous example Tiles view into a rich Javascript popup:
|
|
</para>
|
|
<programlisting language="xml"><![CDATA[
|
|
<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">
|
|
<on-entry>
|
|
<render fragments="hotelSearchForm" />
|
|
</on-entry>
|
|
<transition on="search" to="reviewHotels">
|
|
<evaluate expression="searchCriteria.resetPage()"/>
|
|
</transition>
|
|
</view-state>]]>
|
|
</programlisting>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter> |