Creating an Ajax-Enabled Shopping Cart


Ajax is often used with applications that support drag and drop using the mouse. For example, one application that seems tailor-made for Ajax is a drag-and-drop shopping cart application. Currently on most Internet commerce sites, when you use a shopping cart in online applications, you have to click an Add to Cart button, which takes you to a new page, and you have to get back to the shopping section from there.

Ajax can improve this situation dramatically. With Ajax, all you have to do is to drag the item(s) you want to a shopping cart on the same page. Behind the scenes, the page can send data to the server and get a confirming response back. For example, you might drag a DVD player to a shopping cart icon, and when you drop that item in the cart, your purchase is registered on the server-without a page refresh.

For example, take a look at the Ajax-enabled shopping cart example shown in Figure 8.7.

image from book
Figure 8.7: An Ajax-enabled shopping cart example

In this example, you can drag the DVD player using the mouse, as you see in Figure 8.8.

image from book
Figure 8.8: Dragging a DVD player

When you drop the DVD player in the shopping cart, the server sends back the message “Congratulations, you just bought a fine DVD player,” as you can see in Figure 8.9.

image from book
Figure 8.9: Buying a DVD player

This example shows you how to handle drag-and-drop operations (including working with mouse events) and Ajax. It starts by creating a <div> element for the DVD player. The text you see in Figure 8.7 for the DVD player is simply enclosed in the <div> element:

 <body>   <h1>Buy a DVD player--drag it to the shopping cart</h1>     <div        style="left:180px; top:150px; width:80px; height:60px;">       DVD Player</div>       .       .       . </body>

You can also add additional styles for the cart in a <style> element in the page’s <head> element:

 <style type="text/css">   #dvdplayer {     .     .     .   } </style>

For example, you should set the position style of the DVD player <div> element to absolute, which means you can position this <div> element using the mouse:

 <style type="text/css">   #dvdplayer {     position:absolute;     .     .     .   } </style>

And you should give the DVD player a high value for its z-index property. This property sets the “stacking order” of the <div> with respect to other items in the page. You want to give the DVD player <div> element a high stacking order value so that it rides above other items on the page-in particular, so that the user can drag it on top of the cart <div> element. Here’s how you set the z-index property in this example:

 <style type="text/css">   #dvdplayer {     position:absolute;     z-index:200;     .     .     .   } </style>

You can also set the color of the background as well as the color of text of the DVD player <div> element:

 <style type="text/css">   #dvdplayer {     position:absolute;     z-index:200;     background: #eecc00;     color:#0000FF;   } </style>

That completes the <div> element for the DVD player. You also need a <div> element for the shopping cart:

 <body>    <h1>Buy a DVD player--drag it to the shopping cart</h1>     <div        style="left:180px; top:150px; width:80px; height:60px;">       DVD Player</div>      <div        style="left:350px; top:250px; width:200px; height:100px;">       Shopping Cart</div>  </body>

And you can set additional properties for the cart in the <style> element in the page’s <head> element. For example, to position the cart where you want it, you have to set its position property to absolute:

 <style type="text/css">   #dvdplayer {     position:absolute;     z-index:200;     background: #eecc00;     color:#0000FF;   }    #cart {     position:absolute;     .     .     .   } </style>

You can set its color and background color here as well:

 <style type="text/css">   #dvdplayer {     position:absolute;     z-index:200;     background: #eecc00;     color:#0000FF;   }   #cart {     position:absolute;     background: #00ff00;     color:#000000;   } </style>

That’s it for the cart <div> element. Note that you also need a <div> element in which to display the server’s acknowledgement of your purchase, targetDiv, which looks like this:

   <body>     <h1>Buy a DVD player--drag it to the shopping cart</h1>       <div ></div>       <div          style="left:180px; top:150px; width:80px; height:60px;">         DVD Player</div>       <div          style="left:350px; top:250px; width:200px; height:100px;">         Shopping Cart</div>   </body>

That sets up the <div> elements for the cart, DVD player, and the server’s notification. Now you can start working with the mouse. That all starts with the DVD player <div> element, for which you have to enable dragging and dropping. The process begins when you connect a JavaScript function to the onmousedown event of the DVD player <div> element like this:

 <body>   <h1>Buy a DVD player--drag it to the shopping cart</h1>     <div ></div>      <div        style="left:180px; top:150px; width:80px; height:60px;"       onmousedown="processMouseDown(event);">DVD Player</div>      <div        style="left:350px; top:250px; width:200px;         height:100px;">       Shopping Cart</div>  </body>

The whole process of dragging and dropping starts when the user presses the mouse button on the DVD player, and the onmousedown event connects the mouse press to a JavaScript function named processMouseDown. That begins the mouse handling for this example.

Creating a cross-browser mouse event object

When the user presses the mouse button, the processMouseDown function is called; that function begins by creating a new MouseEvent object:

 function processMouseDown(e) {   var e = new MouseEvent(e);   .   .   . }

What’s that all about? It turns out that working with the mouse differs radically between browsers, so this example starts its mouse work by creating a mouse object that has the same properties, no matter what browser the user has. All the mouse handler functions in this example use this cross-browser mouse object.

In fact, working with the mouse differs from the very start, as soon as the mouse button goes down. The onmousedown event is connected to the processMouseDown function, and passes the current event object to that function:

    <body>     <h1>Buy a DVD player--drag it to the shopping cart</h1>       <div ></div>       <div          style="left:180px; top:150px; width:80px; height:60px;"         onmousedown="processMouseDown(event);">DVD Player</div>       <div          style="left:350px; top:250px; width:200px; height:100px;">         Shopping Cart</div>   </body>

This event object actually only gets passed to the processMouseDown function in the Mozilla/Netscape/Firefox-type browsers. In Internet Explorer, this event object is simply null-you use the window.event object instead.

So the MouseEvent function first tests the event object passed to it; if it exists, it’s stored as a property of the new MouseEvent object with the syntax this.e (“this” refers to the current object):

 function MouseEvent(e) {   if(e) {     this.e = e;   }   .   .   . }

If the event object is null, on the other hand, then you should use the window.event object as the event object, which looks like this:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }   .   .   . }

That stores the event object in the MouseEvent object’s e property. Now it’s time to determine where the mouse event occurred in the Web page. Coordinates in a Web page start in the upper left of the client area. Positive X is to the right, and positive Y is downward.

Note 

The client area is the area where content is displayed, excluding toolbars, menu bars, and so on.

In Mozilla/Netscape/Firefox-type browsers, you use the event object’s pageX property to get the mouse event’s X coordinate. You can test whether that property exists, and if so, store it as the MouseEvent object’s x property like this:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }   if(e.pageX) {     this.x = e.pageX;   } 

On the other hand, if the pageX property doesn’t exist, you should use Internet Explorer’s X coordinate property, clientX:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }   if(e.pageX) {     this.x = e.pageX;   } else {     this.x = e.clientX;   }   .   .   . }

Similarly, when you create the Y coordinate of the mouse location, stored in the MouseEvent object’s y property, first check for the pageY of the Mozilla/Netscape/Firefox browsers:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }    if(e.pageX) {     this.x = e.pageX;   } else {     this.x = e.clientX;   }    if(e.pageY) {     this.y = e.pageY;   }   .   .   . }

If the pageY property doesn’t exist, you should use Internet Explorer’s clientY property instead:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }    if(e.pageX) {     this.x = e.pageX;   } else {     this.x = e.clientX;   }    if(e.pageY) {     this.y = e.pageY;   } else {     this.y = e.clientY;   }   .   .   . }

That creates the e (holding the original event object), x, and y properties of the MouseEvent object.

There’s one more property this object supports: the target property, which holds the element inside of which the mouse event occurred. If you’re dealing with a Mozilla/Netscape/Firefox-type browser, the target element is stored as the event object’s target property:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }   if(e.pageX) {     this.x = e.pageX;   } else {     this.x = e.clientX;   }   if(e.pageY) {     this.y = e.pageY;   } else {     this.y = e.clientY;   }   if(e.target) {     this.target = e.target;   }   .   .   . }

If the target property doesn’t exist, you should use Internet Explorer’s srcElement property:

 function MouseEvent(e) {   if(e) {     this.e = e;   } else {     this.e = window.event;   }   if(e.pageX) {     this.x = e.pageX;   } else {     this.x = e.clientX;    }   if(e.pageY) {     this.y = e.pageY;   } else {    this.y = e.clientY;   }   if(e.target) {     this.target = e.target;   } else {     this.target = e.srcElement;   } }

As you can see, the cross-browser MouseEvent object has taken the whirl of individual browser properties-srcElement, clientX, pageY, and so on-and created a set of properties that are easy to work with in your code, no matter which browser you have:

  • e: The original event object, as created by the browser

  • x: The x coordinate of the mouse

  • y: The y coordinate of the mouse

  • target: The target element, where the mouse event took place

Now instead of worrying about using pageX, clientX, target, or srcElement in your code, all you have to do is to create a new MouseEvent object and use the four cross-browser properties described.

Handling mouse down events

When the mouse button is pressed in the browser, the processMouseDown function is called:

    <body>     <h1>Buy a DVD player--drag it to the shopping cart</h1>       <div ></div>        <div          style="left:180px; top:150px; width:80px; height:60px;"         onmousedown="processMouseDown(event);">DVD Player</div>        <div          style="left:350px; top:250px; width:200px; height:100px;">         Shopping Cart</div>    </body>

The code in that function starts by creating a new cross-browser mouse event object:

 function processMouseDown(e) {   var e = new MouseEvent(e);   .   .   . }

Then the code in processMouseDown starts the dragging process by connecting mouse “listener” functions to the mouse move event (the event that occurs when the user drags the DVD player) and the mouse up event (the event that occurs when the DVD player is dropped). The function that tracks mouse movements is processMouseMove, and the function that tracks mouse up events is processMouseUp. You start the dragging-and-dropping process by connecting functions that will catch mouse move and mouse up events:

 function processMouseDown(e) {   var e = new MouseEvent(e);   addListener("mousemove", processMouseMove);   addListener("mouseup", processMouseUp);   .   .   . }

What is the addListener function? Is it built into all browsers in an (amazing) display of cross-browser programming? No, it’s a function this example creates itself, because the way you connect events to functions varies by browser. The addListener function is passed the type of event you want to track and the callback function that should be called when that event occurs:

 function addListener(type, callback) {   .   .   . }

If the browser’s document object supports the addEventListener method, you can use that method to connect a callback function to an event like this:

 function addListener(type, callback) {   if (document.addEventListener) {     document.addEventListener(type, callback, false);   }   .   .   . }

On the other hand, if the browser’s document object supports the attachEvent method, you can use that to connect a callback function to an event:

 function addListener(type, callback) {   if (document.addEventListener) {     document.addEventListener(type, callback, false);   } else if (document.attachEvent) {     document.attachEvent("on" + type, callback, false);   } }

That’s the function you use in processMouseDown to connect the mouse move and mouse up events to the processMouseMove and processMouseUp functions.

Now that you’re tracking those events, what’s next?

When users move the mouse, you have to move the HTML element they’re dragging yourself. To do that, you should record the location at which the mouse was pressed inside that element. To move an element using dynamic styles, you can position its top left corner to match the new mouse location, but if the user pressed the mouse somewhere inside the element, you have to keep in mind that the upper left corner doesn’t necessarily correspond to the mouse location in the element. To account for that, you can store the X and Y offsets of the mouse with respect to the upper-left corner of the dragged element. For example, here’s how you store the X offset in processMouseDown, as offsetX:

 var offsetX; function processMouseDown(e) {   var e = new MouseEvent(e);   addListener("mousemove", processMouseMove);   addListener("mouseup", processMouseUp);   offsetX = e.x - parseInt(e.target.style.left);   .   .   . }

Here’s what’s happening: the offset is the position of the mouse inside the dragged element, and in the X direction, that’s equal to the x location of the mouse-e.x-minus the left position of the dragged element. To find the left position of the dragged element, you can use the element’s left style property. The dragged element is accessible as e.target, and its style properties are accessible through the style object, e.target.style. The left-hand edge of the element is at position e.target.style.left, but that property is stored as text. To convert from text to a number, you can use the JavaScript parseInt function, so you get offsetX = e.x - parseInt(e.target.style.left);.

Similarly, here’s how you can calculate the Y offset of the mouse inside the dragged element:

 var offsetX, offsetY; function processMouseDown(e) {   var e = new MouseEvent(e);   addListener("mousemove", processMouseMove);   addListener("mouseup", processMouseUp);   offsetX = e.x - parseInt(e.target.style.left);   offsetY = e.y - parseInt(e.target.style.top);   .   .   . }

You’ll use offsetX and offsetY when positioning the dragged element later in this chapter.

Finally, now that the mouse button was pressed, starting a new drag-and-drop process, you can erase any text in the targetDiv <div> element, which will display text from the server:

 function processMouseDown(e) {   var e = new MouseEvent(e);   addListener("mousemove", processMouseMove);   addListener("mouseup", processMouseUp);   offsetX = e.x - parseInt(e.target.style.left);   offsetY = e.y - parseInt(e.target.style.top);   document.getElementById("targetDiv").innerHTML = ""; }

That’s the processMouseDown function: it connects functions to the mouse move and mouse up events, and calculates the offset of the mouse location in the dragged element.

The next step happens when the user starts dragging the mouse.

Handling mouse move events

After starting the dragging operations by pressing the mouse button in a draggable HTML element, the user moves the mouse. Your goal is to make sure the draggable element follows that mouse movement. When the user pressed the mouse button in the DVD player <div> element, the onmousemove event was connected to the processMouseMove function, which looks like this in the code:

 function processMouseMove(e)  {    .    .    .  }

The first step is to convert the mouse event to a cross-browser MouseEvent event object:

 function processMouseMove(e) {   var e = new MouseEvent(e);   .   .   . }

Then you need the new position of the dragged element. You can find the new x position of the element like this:

 function processMouseMove(e) {   var e = new MouseEvent(e);   var x = e.x - offsetX;   .   .   . }

Note 

This action subtracts the x offset of the actual mouse location inside the dragged element in order to find the real new position of the left edge.

then you can set the location of the left-hand edge of the dragged element like this:

 function processMouseMove(e) {   var e = new MouseEvent(e);   var x = e.x - offsetX;   e.target.style.left = x + "px";   .   .   . }

Similarly, you can position the top of the dragged element using the new y position of the mouse:

 function processMouseMove(e) {   var e = new MouseEvent(e);   var x = e.x - offsetX;   e.target.style.left = x + "px";   var y = e.y - offsetY;   e.target.style.top = y + "px"; }

That moves the dragged element to the new location of the mouse. But what about when the user drops the element?

Handling mouse up events

When the user releases the mouse button, that action causes a mouse up event, which means that if the user drags an element, that element is dropped. For example, if the user drags the DVD player <div> element, the drop event is tied to the function processMouseUp:

 function processMouseUp(e) {   .   .   . }

The code in processMouseUp starts by creating a cross-browser event object:

 function processMouseUp(e) {   var e = new MouseEvent(e);   .   .   . }

then the code removes the mouse move and mouse up event handlers, using a function named removeListener:

 function processMouseUp(e) {   var e = new MouseEvent(e);   removeListener("mousemove", processMouseMove);   removeListener("mouseup", processMouseUp);   .   .   . }

The removeListener function removes a callback function from an event, if the document object supports the removeEventListener method:

 function removeListener (type, callback) {   if (document.removeEventListener) {     document.removeEventListener(type, callback, false);   }   .   .   . }

In other browsers, you can use the detachEvent method to do the same thing:

 function removeListener (type, callback) {   if (document.removeEventListener) {     document.removeEventListener(type, callback, false);   } else if (document.detachEvent) {     document.detachEvent("on" + type, callback, false);   } }

After the mouse up and mouse move listener functions have been removed, you have to determine whether the dragged element was dropped inside the cart <div> element. Start by getting an object corresponding to the cart:

 function processMouseUp(e) {   var e = new MouseEvent(e);   removeListener("mousemove", processMouseMove);   removeListener("mouseup", processMouseUp);   var cart = document.getElementById("cart");   .   .   . }

Get the position of the cart, as well as its width and height:

 function processMouseUp(e) {   var e = new MouseEvent(e);   removeListener("mousemove", processMouseMove);   removeListener("mouseup", processMouseUp);   var cart = document.getElementById("cart");   var x = parseInt(cart.style.left);   var y = parseInt(cart.style.top);   var width = parseInt(cart.style.width);   var height = parseInt(cart.style.height);   .   .   . }

then test to make sure the dragged element was dropped inside the cart:

 function processMouseUp(e) {   var e = new MouseEvent(e);    removeListener("mousemove", processMouseMove);   removeListener("mouseup", processMouseUp);   var cart = document.getElementById("cart");   var x = parseInt(cart.style.left);   var y = parseInt(cart.style.top);   var width = parseInt(cart.style.width);   var height = parseInt(cart.style.height);   if(e.x > x && e.x < x + width &&     e.y > y && e.y < y + height){   .   .   .   } }

At this point, you’ve determined that the user dropped the DVD player inside the cart. It’s time to fetch the message from the server, which is stored in a file named buy.txt. You can do that by creating a new XMLHttpRequest object and configuring it to download buy.txt:

 function processMouseUp(e) {   var e = new MouseEvent(e);   .   .   .   if(e.x > x && e.x < x + width &&     e.y > y && e.y < y + height){     var XMLHttpRequestObject = false;     if (window.XMLHttpRequest) {       XMLHttpRequestObject = new XMLHttpRequest();     } else if (window.ActiveXObject) {       XMLHttpRequestObject = new       ActiveXObject("Microsoft.XMLHTTP");     }     if(XMLHttpRequestObject) {       XMLHttpRequestObject.open("GET", "buy.txt");       .       .       .     }   } }

Finally, you can handle the download and display the “Congratulations, you just bought a fine DVD player” text from buy.txt in the targetDiv element in the Web page:

 function processMouseUp(e) {   var e = new MouseEvent(e);     .     .     .     if (window.XMLHttpRequest) {       XMLHttpRequestObject = new XMLHttpRequest();     } else if (window.ActiveXObject) {       XMLHttpRequestObject = new       ActiveXObject("Microsoft.XMLHTTP");     }     if(XMLHttpRequestObject) {       XMLHttpRequestObject.open("GET", "buy.txt");       XMLHttpRequestObject.onreadystatechange = function()       {         if (XMLHttpRequestObject.readyState == 4 &&           XMLHttpRequestObject.status == 200) {             document.getElementById("targetDiv").innerHTML =               XMLHttpRequestObject.responseText;             delete XMLHttpRequestObject;             XMLHttpRequestObject = null;         }       }       XMLHttpRequestObject.send(null);     }   } }

That completes the shopping cart example, which put dragging and dropping and Ajax to work.



Ajax Bible
Ajax Bible
ISBN: 0470102632
EAN: 2147483647
Year: 2004
Pages: 169

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net