Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

ATG White Paper

Implementing Ajax in ATG applications


How to guide on implementing rich user experiences in ATG applications using Ajax.
By Barry Coleman

Master the art of customer experience

ATG White Paper 1 Introduction Ajax (Asynchronous JavaScript And XML) is a web application development technique that was first pioneered by Microsoft in their Outlook Web Access interface. The Microsoft team contributed their XMLHTTP code to the Internet Explorer 4.0 code base. The techniques have been in use since around 1998, but have really only become popular since the beginning on 2005. Jesse James Garrett of Adaptive Path coined the term Ajax in a paper titled Ajax: A New Approach to Web Applications. He describes the technique as: Every user action that normally would generate an HTTP request takes the form of a JavaScript call to the Ajax engine instead. Any response to a user action that doesnt require a trip back to the server such as simple data validation, editing data in memory, and even some navigation the engine handles on its own. If the engine needs something from the server in order to respond if its submitting data for processing, loading additional interface code, or retrieving new data the engine makes those requests asynchronously, usually using XML, without stalling a users interaction with the application. Ajax is a collection of web technologies: HTML, CSS, Document Object Model (manipulated through JavaScript) and the XMLHttpRequest object. It is also the development technique of how to apply them together. Pros and Cons The biggest advantage of using Ajax techniques is that data can be manipulated without having to render the entire page again in the browser. This gives the user a more responsive and continuous user experience. All of the technologies are available on most browsers (certainly all the major browsers) and do not require special plug-ins which may not be available across all platforms. It does require the browser to have JavaScript enabled. One of the major down sides is that most of the constituent technologies have inconsistencies between browser implementations and even between versions of the same browser. ATG has experienced this during the implementation of the ATG Service Suite 2006.1. We spent a significant amount of time in the Quality Assurance group making sure that the application behaved consistently across the supported browsers, ultimately eliminating versions of browsers that could not be made to work consistently. This is something we were comfortable with for that application as it is designed to be used in a call center environment where the agent desktop is closely controlled by IT. It would have been an entirely more taxing problem for a customer facing application. Basics methodologies for using Ajax with ATG There are two core approaches to the process and they can both be used simultaneously as required: 1. Make HTTP calls to JSP pages passing data as query parameters or post data. The JSP renders HTML that is used to replace existing HTML in the documents DOM. In this model the content is rendered on the server so the client doesnt really need to manipulate it. 2. Make HTTP calls to JSP pages or WebServices that return XML. This XML is then parsed on the client using JavaScript and rendered into the appropriate DOM components directly. In the ATG Service Suite 2006.1, we have followed primarily the first model. We have created a simple framework for handling the creation of partial page renderers. A description is beyond the

Implementing Ajax in ATG applications

ATG White Paper 2 scope of this document but if you take a look at the implementation of the Agent application in the Service Suite you can readily discover how it works. For this document we will focus on more concise examples. As an example of both implementation approaches Im going to implement a simple Add to Cart feature that updates an inline shopping cart on a product detail page. This example assumes we are using the ATG Commerce application. Well approach this problem in 2 phases: 1. Well add the inline cart to the product detail page 2. Well add the functionality to add items to the cart Adding the inline cart into the page For this well add a <div> tag to the product detail JSP page:
<div id=quickCart></div>

This will add an empty node to the DOM in the browser that we can manipulate using JavaScript. Now in the <HEAD> section of the JSP we need to add some JavaScript to populate this part of the page. We are going to make a separate request for this information. Heres the basic flow: 1. 2. 3. 4. 5. Get an XMLHttpRequest object Set the URL to be called and the calling method (GET in this case) Register a function to handle the response Send the request Handle method gets called and updates <div> with the response

The request to the server is designed to be asynchronous in nature; although you can specify that XMLHTTPRequest operate synchronously this breaks the paradigm. So we register a handler method to deal with the results from the server. In this case we are going to have the server render an HTML fragment that we will use as the <div> tags innerHTML. Heres the JavaScript:
<SCRIPT type=text/javascript> function getHTTPRequest() { var xmlhttp = false; try { xmlhttp = new ActiveXObject(Msxml2.XMLHTTP); } catch (e) { try { xmlhttp = new ActiveXObject(Microsoft.XMLHTTP); } catch (E) { xmlhttp = false; } } if (!xmlhttp && typeof XMLHttpRequest!=undefined) { xmlhttp = new XMLHttpRequest(); } return xmlhttp; } function updateQuickCart() { var xmlhttp = getHTTPRequest(); xmlhttp.open(GET,/PioneerCycling/en/inline/QuickCartFragment.jsp); xmlhttp.onreadystatechange = function() {

Implementing Ajax in ATG applications

ATG White Paper 3


if (xmlhttp.readyState == 4) { var quickCart = document.getElementById(quickCart); quickCart.innerHTML = xmlhttp.responseText; } } xmlhttp.send(null); } </SCRIPT>

The getHTTPRequest() function accounts for the differences between browser implementations, it handles both new and old version of IE as well as the Mozilla based browsers. On the server side we simply implement QuickCartFragment.jsp as we would any JSP page. It should not have any of the <HTML>, <HEAD> and <BODY> tags though. Heres an example:
<%@ taglib uri=dsp prefix=dsp %> <dsp:page> <dsp:importbean bean=/atg/commerce/order/ShoppingCartModifier/> <dsp:importbean bean=/atg/dynamo/droplet/ForEach/> <dsp:droplet name=ForEach> <dsp:param name=array bean=ShoppingCartModifier.Order.CommerceItems/> <dsp:param name=elementName value=commerceItem/> <dsp:param name=indexName value=commerceItemIndex/> <dsp:oparam name=outputStart> <table> <tr><td>Product</td><td>Quantity</td><td>Price</td></tr> </dsp:oparam> <dsp:oparam name=output> <tr><td> <dsp:valueof param=commerceItem.auxiliaryData.productRef.displayName/> </td><td> <dsp:valueof param=commerceItem.quantity/> </td><td> <dsp:valueof param=commerceItem.priceInfo.amount converter=currency/> </td></tr> </dsp:oparam> <dsp:oparam name=outputEnd> </table> </dsp:oparam> <dsp:oparam name=empty> cart empty </dsp:oparam> </dsp:droplet> </dsp:page>

Only one thing remains and that is to call the updateQuickCart() method when the page loads. This can either be done using the onload attribute of the <BODY> tag or registering a function for the window.onload event: or
<BODY ONLOAD=updateQuickCart()> <SCRIPT type=text/javascript> window.onload = function() { updateQuickCart(); } </SCRIPT>

Now anytime we need to update the view of the cart on this page we can call the updateQuickCart() method in JavaScript and it will replace the current contents of that section of the page without refreshing the entire page.

Implementing Ajax in ATG applications

ATG White Paper 4 Adding an item to the cart In the common Product Details page of an ATG Commerce site you will see a <dsp:include> of an addToCart.jsp page fragment. This page fragment usually contains a <dsp:form> that references the CartModifierFormHandler. In this form youll find something like the following line:
<dsp:input type=submit bean=ShoppingCartModifier.addItemToOrder value=Add to Cart/>

This will cause the browser to package up the form data in a post, submit it to the server with a request for the forms action URI. The server will then process this and return an entire new page (often the cart page or an updated version of the current page). Our new desired behavior is to have the item added to the cart without the page refresh. Weve already seen how to update the page with the content of the cart, now we just need to add the item to the cart. To achieve this we can use the addItemToOrder WebService that is provided as part of the ATG Commerce implementation (enable this by starting your ATG instance with the module DCS.WebServices). Well discuss alternatives after the example. First, we replace the Submit button with a link (probably put a nice image here with mouse over effects and so on). Register a JavaScript method with the onclick attribute of the <IMG> tag:
<dsp:img src=addToCart.gif onclick=addToCart();/>

Now the JavaScript simply need to pull the values of the Sku id, Product id, Order id and Quantity from the elements on the page. Fortunately, the out of the box addToCart.jsp page in PioneerCycling has these available. The following code assume that it can see the previous JavaScript functions:
<SCRIPT type=text/javascript> function addToCart() { /* First accumulate the values from the form */ var addToCartForm = document.getElementById(addToCartForm); var orderId = addToCartForm.orderId.value; var productId = addToCartForm.productId.value; /* Skus can be presented differently so account for the different elements */ var skuId = ; if (document.getElementById(SkuGroup)==null) { skuId = addToCartForm.skuSelectField.value; } else { skuId = addToCartForm.SkuGroup.value; } var quantity = addToCartForm.quantityField.value; /* Now build the request and send it */ var xmlhttp = getHTTPRequest(); xmlhttp.open(POST,/commerce/order/addItemToOrder/addItemToOrder); /* implement a function to receive the response */ xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { /* we are receiving XML this time not text/html */ var rXML = xmlhttp.responseXML; var rNodes = rXML.getElementByTagName(return); /* response is either a commerce item id or an exception

Implementing Ajax in ATG applications

ATG White Paper 5


if its an exception then rNodes will be empty */ if (rNodes == null) { alert(Problem adding item to cart); } else { /* check that the contents of the node are not null */ var rText = rNodes[0].firstChild.nodeValue; if (rText != null) { updateQuickCart(); } else { alert(Problem adding item to cart); } } } } xmlhttp.setRequestHeader(Man, POST /commerce/order/addItemToOrder/addItemToOrder HTTP/1.1); xmlhttp.setRequestHeader(MessageType,CALL); xmlhttp.setRequestHeader(Content-Type,text/xml); /* Now construct the SOAP packet to send to the web service */ xmlhttp.send(<?xml version='1.0' encoding='UTF-8'?>"+"\n\n"+ '<SOAP-ENV:Envelope'+ ' xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"'+ ' xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"'+ ' xmlns:xsd="http://www.w3.org/1999/XMLSchema">'+ '<SOAP-ENV:Body xmlns:ns1="http://www.atg.com/webservices">'+ '<ns1:addItemToOrder SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'+ '<orderId xsi:type="xsd:string">'+orderId+'</orderId>'+ '<productId xsi:type="xsd:string">'+productId+'</productId>'+ '<skuId xsi:type="xsd:string">'+skuId+'</skuId>'+ '<quantity xsi:type="xsd:long">'+quantity+'</quantity>'+ '</ns1:addItemToOrder>'+ '</SOAP-ENV:Body></SOAP-ENV:Envelope>'); } </SCRIPT>

Using the ATG Web Services documentation, and following this example, you should be able to figure out the SOAP packet for the other web services. For instance, this is the XML for the getInventory Web Service:
<?xml version='1.0' encoding='utf-8'?> <SOAP-ENV:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'> <SOAP-ENV:Body xmlns:ns1='http://www.atg.com/webservices'> <ns1:getInventory SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'> <skuIds soapenc:arrayType='xsd:string[2]' xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' xsi:type='soapenc:Array'> <item xsi:type='xsd:string'>sku123456</item> <item xsi:type='xsd:string'>sku234567</item> </skuIds> </ns1:getInventory> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

Implementing Ajax in ATG applications

ATG White Paper 6 Things to watch out for There is one big gotcha: posting to FormHandlers. The ATG FormHandler mechanism has a built in security system. Whenever a form page is rendered the ATG server creates a list of all the elements that were on the page. These are the only elements it will allow to be posted back to the form. This poses a problem because the JavaScript code might not have requested a form page from the server at all. This means that the server wont accept an unsolicited post of data to a FormHandler. This is why I used the web service as it operates directly on the order objects without going through the FormHandlers. As a general pattern it is a good idea to separate as much business logic from Form Handlers as possible. You can then easily set up web services to call the business logic directly (see the ATG Web Service documentation for more details on creating web services from Nucleus components). Most of the major browsers (Internet Explorer, Firefox, Mozilla, Safari, etc.) will send and cookies received with the original response back to the server with each XMLHttpRequest. This ensures that you get back to the same session objects on the ATG server. Other implementations may not do this. If you discover a browser that doesnt and you need to support it, you should add the jsessionid to the URL in the XMLHttpRequest.open() method call. You can retrieve the session id from the SessionCookie using this JavaScript:
function getSessionIdFromCookie() { if (document.cookie == "") return null; var cookies = document.cookie.split(";"); for(var i=0;i<cookies.length;i++){ var pair = cookies[i].split("="); if (pair[0]==JSESSIONID) return unescape(pair[1]); } }

So your open code would be:


xmlhttp.open(POST, /commerce/order/addItemToOrder/addItemToOrder;jsessionid=+ getSessionIdFromCookie());

If you have changed the cookie name youll need to adjust this code accordingly. You can look at the sessionCookieName attribute of the /atg/dynamo/servlet/sessiontracking/SessionManager component. Other Toolkits and Techniques So far weve discussed the basic methodologies. While this is a good starting point it is clear that this could become unwieldy really quickly. You can either build a client JavaScript framework for yourself from these basic building blocks or use one of the available open source or commercial ones. The toolkits break down into three basic categories: 1. Remote Invocation/Object Model Frameworks 2. Partial Page Rendering Frameworks 3. Complete UI Frameworks Remote Invocation/Object Model Frameworks basically provide a way of having the server side Java objects reflected as JavaScript objects on the client side. Calls to JavaScript methods are marshaled into calls to the server object and the return values marshaled back into JavaScript data types and objects. This is basically RMI for JavaScript. A good example of this is DWR Implementing Ajax in ATG applications

ATG White Paper 7 (Direct Web Remoting) available at http://dwr.dev.java.net. This simple toolkit is easy to integrate with ATG and provides access to components of all scopes (see separate paper Ajax development of ATG applications using DWR). Partial Page Rendering allows you to break the page up into zones or regions and have those refreshed using Ajax. These are usually JSP tag libraries that help you minimize the amount of JavaScript code that you need to write by hand. A good example is AjaxAnywhere http://ajaxanywhere.sourceforge.net. Complete UI frameworks focus mainly on the client side and introduce nothing (or at least very little) on the server side. Open source examples are: Prototype (http://prototype.conio.net) and Dojo (http://dojotoolkit.org). There are also much more complete commercial toolkits available from companies such as BackBase (http://www.backbase.com), JackBe (http://www.jackbe.com), and Isomorphic SmartClient (http://www.isomorphic.com). There are also frameworks that include server components as well, such as Nexaweb (http://www.nexaweb.com) and Casabac (http://www.oisoft.com/index.pl/casabac). All of these tool kits have their merits and their drawbacks. Some of the commercial ones include GUI design tools to aid in layout. They all integrate with the ATG server infrastructure using the techniques outlined in this paper. Bibliography Ajax: A New Approach to Web Applications by Jesse James Garrett http://www.adaptivepath.com/publications/essays/archives/000385.php ATG Web Service Documentation http://www.atg.com/repositories/ContentCatalogRepository_en/manuals/ATG7.1/intframe/index.ht ml ATG Commerce Web Service Documentation http://www.atg.com/repositories/ContentCatalogRepository_en/manuals/ATG7.1/commprog/com mprog1901.html

Implementing Ajax in ATG applications

You might also like