Implementing a Shopping Cart using Ajax

an article added by: Sonja Lande at 06012007


In: Categories » » AJAX » Implementing a Shopping Cart using Ajax

The shopping cart example will be implemented in abbreviated form for explanation purposes. The solution will focus on the generation of the unique URL and using that unique URL when buying something.

The Initial Solution

The following illustrates the shopping example source code.

   Source: /client/ajaxrest articles/architecture/shoppingcart.html
 <html>
 <head>
 <title>Shopping cart</title>
 <script language="JavaScript"  src="/scripts/jaxson/common.js"></script>
 <script language="JavaScript"  src="/scripts/jaxson/communications.js"></script>
 </head>
 <script type="text/javascript">
   var  unique = new UniqueURL( "/pyservices/shopping/cart/getone");
   unique.haveIt = function() {
   document.getElementById(  "status").innerHTML = "Have shopping cart";
   }
   function  Initialize() {
   unique.getIt();
   }
   function CustomerDetails() {
   var obj = new Object();
   obj.data = "address=...";
   obj.length = obj.data.length;
   obj.mimetype =  "application/x-www-form-urlencoded";
   return obj;
   }
   function BuyItems() {
   if( unique.uniqueURL != null) {
   var asynchronous =  FactoryHttp.getAsynchronous();
   asynchronous.settings = {
   onComplete : function(xmlhttp) {
   // Process the data ...
   unique.uniqueURL  = null;
   unique.getIt();
   }
   }
   asynchronous.post( unique.uniqueURL  + "/checkout", CustomerDetails());
   }
   }
 </script>
 <body onload="Initialize()">
 <input type="button"  value="Buy it" onclick="BuyItems()" />
 <div id="status"></div>
 <div id="error"></div>
 </body>
 </html>

In the source code example, the bold code represents the pieces of functionality that relate to a specific use of UniqueURL. The HTML page in an overall context represents the parent page that everyone uses to get a shopping cart and buy some items. When the page is loaded, the body.onload event is triggered, causing the Initialize function to be called. In the implementation of Initialize, unique.getIt is called, which results in a unique URL that represents a shopping cart.

By adding the unique URL code to the body.onload event, you’re assured that whoever visits the HTML page will have a shopping cart at their disposal. The generated URL is used whenever users click on the Buy It button, triggering the function called BuyItems. The general implementation of BuyIt is not important, because what you’re doing is posting the last remaining details to buy whatever users have added to the shopping cart. In the asynchronous.post method call, the URL used is unique.uniqueURL. When the purchase has cleared in the onComplete implementation, the uniqueURL data member is cleared and a new, unique shopping-cart URL is retrieved. The code provides an understanding of how to use the unique URL, but you must understand the following considerations:

• When a unique URL, such as /pyservices/shopping/cart/122343, is returned, the client appends the identifier /checkout. Using a nonappended URL would require the URL to accept POST and GET requests for multiple data structures, and that would be non-REST compliant. On the client side, appending an identifier is not a big deal, but on the server, it does become a big deal, as will be discussed shortly.

• The example HTML page doesn’t include the code to search, browse, and add items to the HTML page. You could use two solutions: content injection or an iframe. Using content injection, the catalog items would be pieces of HTML code that would be added to the current HTML page using the innerHTML property. The other approach is to use a floating iframe, which allows you to separate the display of the catalog items from the manipulation.

• In the case of the shopping cart, the owner of the unique URL is the client. This raises the question, “If the users press the page refresh, how will they remember what they were referencing?” The server won’t tell the clients what the unique URL is. The clients can manage this using client-side cookies, as will be illustrated shortly.

Keeping Track of Unique URLs

Typically, Web application frameworks use cookies to keep server-side session objects. While it might seem that server-side session objects solve many problems, they in fact can cause many problems. Let’s say you’re writing a service-oriented architecture (SOA) client that uses Web services nowhere in the Web service documentation will you ever find instructions on how to keep session, because that’s how code is written. Remove the term Web service and use a remote procedure call. By default, a remote procedure call won’t remember who called it. Remote procedure calls expect the caller to remember that, as that is the right approach. To give you a real-life example of why it’s bad to use server-side sessions, let’s say you’re shopping on Amazon.com, and you decide to purchase some things. You’re not going to pay for the contents in your shopping cart, because your mother has decided to purchase everything as a birthday present. In a real-life grocery store, having your mother purchase the contents of your shopping cart is as easy as handing her the shopping cart.

At Amazon.com, each and every user gets a single shopping cart. Therefore, to have your mother pay for the contents, you must manually create a list that you email to your mother. Or you could ask your mother for her credit card details. The first option is easy to do, but it is time consuming and “lame,” as it requires you to write out the contents of your shopping cart and then have her add the items to her shopping cart. It’s as if you go into a store, fill the cart, and then create a list of items in the cart and hand that list to your mother. Your mother then has to race around the grocery store and fill up her cart with the same items so that she can pay. The second option does not require any such extra effort, but it does require your mother trusting you with her credit card details. I’m sure your mother would trust you, but she would probably be uneasy, as would anybody. As you can see, there is no viable option involving server-side, session-based URLs.

The only viable option is to stop using server-side, session-based URLs and start using unique URLs with the client managing the references to the URL. Using client-managed unique URLs opens new possibilities. For example, let’s say that you create a TV, radio, and sound system and add those items to a shopping cart. Then as an added value service, you promote your shopping cart, and whenever anybody wants to purchase your super sound system, they only pay for the shopping cart and don’t have to go around the site finding the individual items. In theory, you could create thousands of different shopping carts with different configurations. However, you can’t do that type of added value today with server-side, session-based URLs. Many say HTTP cookies are bad, but it depends on how cookies are used. I consider cookies as a supporting role for any type of implementation. Now let’s talk about client-side cookies and delay a more in-depth cookie discussion until later in this article. There’s no real difference between a client-side or server-side cookie, because a cookie is a token held by the client and sent to the server. The client or server can assign the token, and in the case of the shopping cart, the client will assign the cookie. The cookie that is assigned is the unique URL, and the modified shopping cart code is as follows (note that only the code has been abbreviated for clarity purposes):

   <script type="text/javascript">
   var unique = new UniqueURL(  "/pyservices/shopping/cart/getone");
   unique.haveIt = function() {
   document.getElementById(  "status").innerHTML = "Have shopping cart";
   createCookie(  "shoppingcart", unique.uniqueURL, 2);
   }
   function Initialize() {
   var  url = readCookie( "shoppingcart");
   if(  url == null || url.length == 0) {
   unique.getIt();
   }
   else  {
   document.getElementById(  "status").innerHTML =
   "already  have a shopping cart";
   unique.uniqueURL  = url;
   }
   }
   function CustomerDetails() {
   var obj = new Object();
   obj.data = "address=...";
   obj.length = obj.data.length;
   obj.mimetype =  "application/x-www-form-urlencoded";
   return obj;
   }
   function BuyItems() {
   if( unique.uniqueURL != null) {
   var asynchronous = FactoryHttp.getAsynchronous();
   asynchronous.settings = {
   onComplete : function(xmlhttp) {
   // Process the data ...
   unique.uniqueURL = null;
   eraseCookie(  "shoppingcart");
   unique.getIt();
   }
   }
   asynchronous.post( unique.uniqueURL,  CustomerDetails());
   }
   }
   </script>

The bold code represents the code related to managing a cookie. In particular, three as-of-yet still undefined functions are used: createCookie, readCookie, and eraseCookie. These three functions are used to write, read, and delete a cookie. The functions have been geared toward ease of use, making it as simple as possible to read and write key-value pairs. The key is a cookie name, and the value is a cookie value. The logic of the cookie functionality is as follows:

• When the page is loaded, the Initialize function checks using the function readCookie to see if a cookie with a name shoppingcart exists. If the cookie exists, then it is not necessary to create a new cookie, but the cookie value has to be assigned to the data member unique.uniqueURL. If the cookie does not exist, it means that there is no associated shopping cart, and thus the function unique.getIt needs to be called.

• If a cookie has to be retrieved using the method unique.getIt, then when the unique URL is generated, the method unique.haveIt is called. In the implementation of unique.haveIt, the cookie shoppingcart is assigned the value of the data member unique.uniqueURL with an expiry of two days.

• When the shopping cart has been paid and a new unique URL is generated, the existing cookie is erased using the function eraseCookie. The implementation of the cookie routines manipulates the document.cookie object. The document.cookie object returns all cookies applicable to the current domain. The following code shows the implementation of the cookie2 functions:

   function createCookie(name,value,days) {
   if (days) {
   var date = new Date();
   date.setTime(date.getTime()+(days*24*60*60*1000));
   var expires = ";  expires="+date.toGMTString();
   }
   else var expires = "";
   document.cookie  = name+"="+value+expires+"; path=/";
   }
   function readCookie(name) {
   var nameEQ = name + "=";
   var  ca = document.cookie.split(';');
   for(var i=0;i < ca.length;i++) {
   var c = ca[i];
   while (c.charAt(0)==' ') c =  c.substring(1,c.length);
   if (c.indexOf(nameEQ) == 0) return  c.substring(nameEQ.length,c.length);
   }
   return null;
   }
   function eraseCookie(name) {
   createCookie(name,"",-1);
 }

The bold code illustrates how the document.cookie object is manipulated. The manipulation is rather peculiar and completely unorthodox. In the implementation of createCookie, a buffer is created and then assigned to document.cookie. Usually an assignment to a data member resets the value of the data member. Not so with the document.cookie data member. Assigning the data member either creates a new cookie or reassigns the value of an existing cookie.

In the implementation of createCookie, the parameter days assign a time to the cookie being created, indicating that the cookie will expire. If the cookie and the function createCookie are not associated with a date time, then the cookie would expire the moment the browser is closed. When reading the data member document.cookie, the cookies applicable to the currently loaded domain and document are retrieved. The following could be an example value of document.cookie:

 cc=value1;shoppingcart=/pyservices/shopping/cart/toRedirected

The value of document.cookie is problematic, because it is a string that contains multiple cookies. To find a single cookie, the string has to be parsed. The implementation of readCookie automatically manages the parsing and retrieves the value for a particular cookie identifier. The function eraseCookie uses the createCookie function to delete a cookie. Again, this is unorthodox, but it uses the functionality where assigning an expired date to a cookie will automatically delete the cookie.

legal notice

Our website is not responsible for the information contained by this article. Web-articles is a free articles resource.
Suggestion: If you need fresh, daily updated content for your website, feel free to use our service. Click here for more information.

Useful tools and features

Link to this article from your page    Send this article to you or to a friend
If you like this article (tutorial), please link to it from your web page using the information above.

related articles

1. Testing a Dynamic Contract with Ajax
Coding the Contract Using Test-Driven Development Techniques Coding the contract using agile and test-driven development techniques requires writing a number of tests and implementing aMock URL layer. Problem You want to code the contract using these development techniques. Solution To demonstrate, let’s define a use case, implement the use case as a contract, write a test case(s) to implement the contract, implement the contract in the Mock URL, and finally...

2. Testing the Client Side Logic
Problem You want to effectively test your application’s client-side logic. Theory Testing GUI code tends not to be a productive task because of the complications that arise. The main complication is how to test the correctness of a user interface. Imagine a situation where clicking a button causes a table to be filled with data. Now imagine that when a check box is checked and the button is clicked again, a different table is filled with content. The fact that clicking the same button results in two ...

3. Understanding JavaScript and Types
Understanding JavaScript and Types Problem You want to work around the fact that JavaScript does not have types declared for its variables. Theory JavaScript code does not have any variables with a declared type. The lack of typed variables is apparent when you declare functions. That said, not having typed variable declarations does not mean JavaScript has no types or no type safety. Let’s start out with the simple declaration of a function, as illustrated by the following ex...

4. Coding Using Conventions and Not Configurations
Coding Using Conventions and Not Configurations Problem You want to make your JavaScript constructs more efficient by applying the Rails “convention over configuration” principle to them. Theory You may already be familiar with the programming platform Ruby on Rails, which is used to build Web applications. The focus of this recipe is not Ruby on Rails, but one aspect of Ruby on Rails namely, convention over configuration (see http://en.wikipedia.org/wiki/ Ruby_on_Rails for m...

5. Advantage of parameterless functions in JavaScript
Using Parameterless Functions Problem You want to take advantage of parameterless functions in JavaScript. Theory JavaScript functions for the most part have parameters. You may think that the previous sentence states the obvious after all, without parameters, what data could be passed to a function? JavaScript has the ability to declare functions that have no parameters, even though the caller of the function has passed parameters to the function. For example, let’s look at...

6. JavaScripot Functions
Treating Functions Like Objects Problem You want to take advantage of the fact that functions are objects (remember, everything is an object in JavaScript). Theory Many people think that a function is some keyword used in JavaScript. A function is also an object that can be manipulated. Knowing that a function is an object makes it very interesting from the perspective of writing JavaScript code, because the code can treat the function like another other object. This mean...

7. Implementing an Error and Exception Handling Strategy
Implementing an Error and Exception Handling Strategy Problem You want to implement a clean error and exception handling strategy in your applications, to make them run more smoothly. Theory Of course, you might argue that one error is a dialog box and the other is generated in the JavaScript console. The fact that one browser uses a dialog box to show an error and the other does not is a browser issue, not an error issue. A concise way of classifying the two errors is to ...

8. Understanding the Behavior of Variables When Implementing Recursion
Understanding the Behavior of Variables When Implementing Recursion Problem You want to implement recursion in JavaScript, and you also want to understand how variables will behave under those circumstances. Theory In JavaScript, you do not need to declare the variable type, or even declare the variable. For example, the following code works perfectly: if( counter == 1) { buffer = "counter is 1"; } document.getEle...

9. Using Functions to Initialize and Make Decisions JavaScript
Using Functions to Initialize and Make Decisions Problem You want to use functions to initialize and make decisions. Theory Usually when you write a piece of code where a change of logic needs to take place based on a context, you use a decision structure. For example, say you are implementing a light switch using a program. You turn on the light if the light is off, and you turn off the light if the light is on. The behavior of the program is determined by the conditions. One example behavior t...

10. Understanding the Ramifications of Duck Typed Code
Understanding the Ramifications of Duck Typed Code Problem You want to understand where to best use duck typing and the issues you should be aware of when using it. Theory There is a difference between a value type and a reference type in JavaScript. Even for a reference type, there is a difference between defining the reference as a value or a pure reference. But should you even care about the difference? Is it something that you need to be aware of? It is when you are...