Skip to main content

An AJAX Based Shopping Cart with Drap Drop Item Effect


An AJAX Based Shopping Cart with PHP, CSS & jQuery




An AJAX Based Shopping Cart





In this tutorial we will create an AJAX Based Shopping Cart with Drag and Drop feature.You can easily use this shopping cart in you store.All the products are going to be stored in a MySQL database, with PHP showing and processing the data.



So go ahead, download the demo files and start reading.








Step 1 – the MySQL Database




If you want to set up a working demo, you’ll need to execute the following SQL code in your database manager (e.g. phpMyAdmin). It will set up the table and insert a few products. The code is also available in table.sql in the demo files.



table.sql



CREATE TABLE IF NOT EXISTS `internet_shop` (
`id` int(6) NOT NULL auto_increment,
`img` varchar(32) collate utf8_unicode_ci NOT NULL default '',
`name` varchar(64) collate utf8_unicode_ci NOT NULL default '',
`description` text collate utf8_unicode_ci NOT NULL,
`price` double NOT NULL default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `img` (`img`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=7 ;

INSERT INTO `internet_shop` VALUES(1, 'iPod.png', 'iPod', 'The original and popular iPod.', 200);
INSERT INTO `internet_shop` VALUES(2, 'iMac.png', 'iMac', 'The iMac computer.', 1200);
INSERT INTO `internet_shop` VALUES(3, 'iPhone.png', 'iPhone', 'This is the new iPhone.', 400);
INSERT INTO `internet_shop` VALUES(4, 'iPod-Shuffle.png', 'iPod Shuffle', 'The new iPod shuffle.', 49);
INSERT INTO `internet_shop` VALUES(5, 'iPod-Nano.png', 'iPod Nano', 'The new iPod Nano.', 99);
INSERT INTO `internet_shop` VALUES(6, 'Apple-TV.png', 'Apple TV', 'The new Apple TV. Buy it now!', 300);




After this, you should fill in your MySQL credentials in connect.inc.php.




Step 2 – the XHTML




First we start off with our main markup.



demo.php




<div id="main-container"> <!-- the main container element -->
<div class="tutorialzine"> <!-- some headings -->
<h1>Shopping cart</h1>
<h3>The best products at the best prices</h3>
</div>
<div class="container"> <!-- the first section - products -->
<span class="top-label">
<span class="label-txt">Products</span> <!-- section label -->
</span>
<div class="content-area">
<div class="content drag-desired"> <!-- assigning a common content class and an individually targeted drag-desired class -->
<?php
// php code that generates the products
?>

<div class="clear"></div> <!-- clearing the floats -->
</div>
</div>
<div class="bottom-container-border"> <!-- bottom part of the section -->
</div>
</div> <!-- closing the products section -->
<div class="container"> <!-- the second section - shopping cart -->
<span class="top-label">
<span class="label-txt">Shopping Cart</span> <!-- label for the section -->
</span>
<div class="content-area">
<div class="content drop-here"> <!-- content class, shared with the product section above, and the targeted drop-here class -->
<div id="cart-icon">
<img src="img/Shoppingcart_128x128.png" alt="shopping cart" class="pngfix" width="128" height="128" /> <!-- using the pngfix class -->
<img src="img/ajax_load_2.gif" alt="loading.." id="ajax-loader" width="16" height="16" /> <!-- the rotating gif - hidden by default and shown during ajax interactions -->
</div>
<form name="checkoutForm" method="post" action="order.php"> <!-- the form -->
<div id="item-list"> <!-- in this div we insert all the products in the shopping cart -->
</div>
</form> <!-- closing the form -->
<div class="clear"></div> <!-- clearing -->
<div id="total"></div> <!-- the total price goes here -->
<div class="clear"></div> <!-- clearing the floats -->
<a href="" onclick="document.forms.checkoutForm.submit(); return false;" class="button">Checkout</a> <!-- the submit button, hidden by default, notice the onclick attribute -->
</div>
</div>
<div class="bottom-container-border"> <!-- bottom part of the section -->
</div>
</div><!-- closing the main container -->





As you can see, we’ve organized our content into two main sections, which are almost identical in the XHTML markup they use – the first one, where all the products are displayed, and second one, acting as a shopping card.



Below you can see a detailed explanation of the structure of the product section.




An AJAX Based Shopping Cart with PHP, CSS & jQuery




The products are generated by our PHP code, as you can see on line 18. We are digging deeper into this in a few minutes. Now lets take a look at how we turned the XHTML layout into a finished design.




Step 3 – the CSS




This time the CSS code is quite long, so I’m going to split it into parts.



demo.css




body,h1,h2,h3,p,td,quote,small,form,input,ul,li,ol,label{
/* resetting some of the styles for browser compatibility */
margin:0px;
padding:0px;
font-family:Arial, Helvetica, sans-serif;
}

body{
color:#555555;
font-size:13px;
background-color:#282828;
}

.clear{ /* implementing the clear-fix hack for fixing floated layouts */
clear:both;
}

#main-container{ /* this is the main container, holding the two sections */
width:700px;
margin:20px auto;
}

.container{ /* the main container of our content sections - the products and the shopping cart */
margin-bottom:40px;
}

.top-label{ /* the outer span comprising the label */
background:url(img/label_bg.png) no-repeat; /* showing the left part of label_bg.png - a wide round-cornered image */
display:inline-block;
margin-left:20px;
position:relative;
margin-bottom:-15px; /* the whole label is lowered on the product section */
}

.label-txt{ /* the inner span - red border in the illustration above */
background:url(img/label_bg.png) no-repeat top right; /* shows the right part of the wider label_bg.png */
display:inline-block;
font-size:10px;
height:36px;
margin-left:10px; /* leaves space on the left, so that the outer span can show its background */
padding:12px 15px 0 5px;
text-transform:uppercase;
}

.content-area{ /* The top part of the rounded container image, see the illustration above */
background:url(img/container_top.png) no-repeat #fcfcfc;
padding:15px 20px 0 20px;
}

.content{ /* shared by the two sections */
padding:10px;
}

.drag-desired{ /* individually targeted properties */
background:url(img/drag_desired_label.png) no-repeat top right;
padding:30px;
}

.drop-here{ /* not shared with the other sections */
background:url(img/drop_here_label.png) no-repeat top right;
}

.bottom-container-border{ /* the bottom rounded graphic, that completes the section */
background:url(img/container_bottom.png) no-repeat;
height:14px;
}

.product{ /* styling the products */
border:2px solid #F5F5F5;
float:left;
margin:15px;
padding:10px;
}

.product img{
cursor:move;
}

p.descr{
padding:5px 0;
}

small{
display:block;
margin-top:4px;
}

.tooltip{ /* the tooltips, this div is created by the simpletip plugin */
position: absolute;
top: 0;
left: 0;
z-index: 3;
display: none;

background-color:#666666;
border:1px solid #666666;
color:#fcfcfc;

padding:10px;

-moz-border-radius:12px; /* rounded corners */
-khtml-border-radius: 12px;
-webkit-border-radius: 12px;
border-radius:12px;
}





Now lets take a look at the styles that target the shopping cart section.




#cart-icon{	/* the div that contains the shopping cart icon */
width:128px;
float:left;
position:relative; /* changing the position to relative so that ajax-loader is positioned relative to it */
}

#ajax-loader{
position:absolute; /* absolute positioning makes an element relative to its parent if the latter has positioning different from the default */
top:0px;
left:0px;
visibility:hidden;
}

#item-list{ /* the contents of the shopping cart goes into this div */
float:left;
width:490px;
margin-left:20px;
padding-top:15px;
}

a.remove,a.remove:visited{ /* the REMOVE link */
color:red
;
font-size:10px;
text-transform:uppercase;
}
#total{ /* the total cost div */
clear:both;
float:right;
font-size:10px;
font-weight:bold;
padding:10px 12px;
text-transform:uppercase;
}

#item-list table{ /* every product in the shopping cart is positioned inside the item-list div */
background-color:#F7F7F7;
border:1px solid #EFEFEF;
margin-top:5px;
padding:4px;
}

a.button,a.button:visited{ /* the CHECKOUT button */
display:none
;

height:29px;
width:136px;

padding-top:15px;
margin:0 auto;
overflow:hidden;

color:white;
font-size:12px;
font-weight:bold;
text-align:center;
text-transform:uppercase;

background:url(img/button.png) no-repeat center top; /* showing only the top part of the background image */
}
a.button:hover{
background-position:bottom
; /* on hover we show the bottom part of the image */
text-decoration:none;
}
/* Some less interesting classes */
a, a:visited {
color:#00BBFF
;
text-decoration:none;
outline:none;
}
a:hover{
text-decoration:underline
;
}
h1{
font-size:28px;
font-weight:bold;
font-family:"Trebuchet MS",Arial, Helvetica, sans-serif;
}

h2{
font-weight:normal;
font-size:20px;

color:#666666;
text-indent:30px;
margin:20px 0;
}

.tutorialzine h1{
color:white;
margin-bottom:10px;
font-size:48px;
}

.tutorialzine h3{
color:#F5F5F5;
font-size:10px;
font-weight:bold;
margin-bottom:30px;
text-transform:uppercase;
}

.tutorial-info{
color:white;
text-align:center;
padding:10px;
margin-top:-20px;
}





As any front-end developer will tell you, we have something missing here. You guessed it – special treatment for IE6.



I personally plan to stop supporting IE6 soon in my projects altogether – if it wasn’t for it, the above code would have been at least a quarter shorter, and it would have taken a lot less time to debug.



But anyway, here is how we target IE6 specifically:



demo.php








There. Now lets take a look at the PHP backend.




An AJAX Based Shopping Cart with PHP, CSS & jQuery







Click Next to Readmore.....





Step 4 – PHP




We use PHP in a number of ways and places. First lets look at how the product list is generated on the main page.



demo.php



$result = mysql_query("SELECT * FROM internet_shop");	// selecting all the products
while($row=mysql_fetch_assoc($result))
{
echo '<div class="product"><img src="img/products/'.$row['img'].'" alt="'.htmlspecialchars($row['name']).'" width="128" height="128" class="pngfix" /></div>';
}




Another place where we use PHP is in tips.php, which takes an image file name as a parameter, checks which product is associated with that image, and outputs the tool tip data as html. This is later used by the simpletip plugin.



ajax/tips.php



define('INCLUDE_CHECK',1);require "../connect.php";
if(!$_POST['img']) die("There is no such product!");
$img=mysql_real_escape_string(end(explode('/',$_POST['img'])));
$row=mysql_fetch_assoc(mysql_query("SELECT * FROM internet_shop WHERE img='".$img."'"));
if(!$row) die("There is no such product!");
echo '<strong>'.$row['name'].'</strong>
<p class="descr">'
.$row['description'].'</p>
<strong>price: $'
.$row['price'].'</strong>
<small>Drag it to your shopping cart to purchase it</small>'
;




We also use PHP to return the necessary data for the addition of products in the shopping cart. The difference is that this time we return the data as JSON (a javascript object).



ajax/addtocart.php




define('INCLUDE_CHECK',1);require "../connect.php";
if(!$_POST['img']) die("There is no such product!");
$img=mysql_real_escape_string(end(explode('/',$_POST['img'])));$row=mysql_fetch_assoc(mysql_query("SELECT * FROM internet_shop WHERE img='".$img."'"));
echo '{status:1,id:'.$row['id'].',price:'.$row['price'].',txt:\'\
\
<table width="100%" id="table_'
.$row['id'].'">\
<tr>\
<td width="60%">'
.$row['name'].'</td>\
<td width="10%">$'
.$row['price'].'</td>\
<td width="15%"><select name="'
.$row['id'].'_cnt" id="'.$row['id'].'_cnt" onchange="change('.$row['id'].');">\
<option value="1">1</option>\
<option value="2">2</option>\
<option value="3">3</option></slect>\
\
</td>\
<td width="15%"><a href="#" onclick="remove('
.$row['id'].');return false;" class="remove">remove</a></td>\
</tr>\
</table>\'}'
;





The outputted object has status, id, price and txt properties. These are used by our AJAX functions as you’ll see in a moment.



Notice how I’ve escaped each line of the string with a backslash. This is done because javascript does not support multiline strings.



The last place where we use PHP is in order.php, which is used to process the orders. Currently, it just outputs your order. You could modify it to include an email form, paypal functionality, or anything that will make it into a functional online shop.



order.php




<?php

define(
'INCLUDE_CHECK',1);require "connect.php";
if(!$_POST) // if there is no data submitted to the form
{
if($_SERVER['HTTP_REFERER']) // redirect
header(
'Location : '.$_SERVER['HTTP_REFERER']);
exit; // and exit
}
?>

<!-- XHTML code.. -->
<?php
$cnt = array();$products = array();
foreach($_POST as $key=>$value)
{
$key=(int)str_replace('_cnt','',$key);
$products[]=$key; // store the product ids in an array
$cnt[$key]=$value; // create a key / value pair where for each product id there is a corresponding value being the number of products
purchased}
$result = mysql_query("SELECT * FROM internet_shop WHERE id IN(".join($products,',').")"); // selecting all the products with the IN() function
if(!mysql_num_rows($result)) // no products found
{
echo '<h1>There was an error with your order!</h1>';
}
else
{
echo '<h1>You ordered:</h1>';
while($row=mysql_fetch_assoc($result))
{
echo '<h2>'.$cnt[$row['id']].' x '.$row['name'].'</h2>';
$total+=$cnt[$row['id']]*$row['price'];
}

echo '<h1>Total: $'.$total.'</h1>';
}
?>





This concludes the PHP section. The only thing that is left is some jQuery magic.



An AJAX Based Shopping Cart with PHP, CSS & jQuery




Step 5 – jQuery




We will utilize jQuery to the fullest, so we will need to include the additional jQuery UI library as well as the basic library.



<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
<script type="text/javascript" src="simpletip/jquery.simpletip-1.3.1.pack.js"></script> <!-- the jQuery simpletip plugin -->
<script type="text/javascript" src="script.js"></script> <!-- our script.js file -->




Now we can continue with our script.



script.js




var purchased=new Array();	//an array containing all the products we've purchased so far
var totalprice=0; //the total price

$(
document).ready(function(){

$(
'.product').simpletip({ //using the simpletip plugin

offset:[
40,0],
content:
'<img style="margin:10px;" src="img/ajax_load.gif" alt="loading" />', // default content
onShow:
function(){

var param = this.getParent().find('img').attr('src');
// fix for IE6
if($.browser.msie && $.browser.version=='6.0')
{
param =
this.getParent().find('img').attr('style').match(/src=\"([^\"]+)\"/);
param = param[
1];
}

// after the tooltip is shown, load the tips.php file and pass the image name as a parameter
this.load('ajax/tips.php',{img:param});
}

});

$(
".product img").draggable({ // enable all product images to be dragged

containment:
'document',
opacity:
0.6,
revert:
'invalid',
helper:
'clone',
zIndex:
100

});

$(
"div.content.drop-here").droppable({ // convert the shopping cart to a droppable

drop:
function(e, ui)
{
var param = $(ui.draggable).attr('src');
// IE6 fix
if($.browser.msie && $.browser.version=='6.0')
{
param = $(ui.draggable).attr(
'style').match(/src=\"([^\"]+)\"/);
param = param[
1];
}

addlist(param);
// the special addlist function - see below
}

});

});





Below is the second part of script.js.




function addlist(param){
// the addlist function ads a product to the shopping cart

$.ajax({
// sending an ajax request to addtocart.php
type:
"POST",
url:
"ajax/addtocart.php",
data:
'img='+encodeURIComponent(param), // the product image as a parameter
dataType:
'json', // expecting json
beforeSend:
function(x){$('#ajax-loader').css('visibility','visible');}, // showing the loading gif
success:
function(msg){

$(
'#ajax-loader').css('visibility','hidden'); // hiding the loading gif animation
if(parseInt(msg.status)!=1)
{
return false; // if there has been an error, return false
}
else
{
var check=false;
var cnt = false;

for(var i=0; i<purchased.length;i++)
{
if(purchased[i].id==msg.id) // find if we have already bought this prduct
{
check=
true;
cnt=purchased[i].cnt;

break;
}
}

if(!cnt) // if we haven't bought it yet, or we have removed it from the purchases, we insert it in the shopping cart
$(
'#item-list').append(msg.txt);

if(!check) // if we haven't bought it yet, insert it in the purchased array
{
purchased.push({id:msg.id,cnt:
1,price:msg.price});
}

else // else if we've bought it
{
if(cnt>=3) return false; // 3 products of type max

purchased[i].cnt++;
$(
'#'+msg.id+'_cnt').val(purchased[i].cnt); // update the select box
}

totalprice+=msg.price;
// recalculate the price
update_total();
// update the total div

}

$(
'.tooltip').hide(); // hiding the tooltip (sometimes it stays on screen after the drag)

}
});
}
function findpos(id) // a helper function that finds the position at which the product is inserted in the array, returns the position{
for(var i=0; i<purchased.length;i++)
{
if(purchased[i].id==id)
return i;
}

return false;
}
function remove(id) // remove a product from the shopping cart{
var i=findpos(id); // find its position in the array

totalprice-=purchased[i].price*purchased[i].cnt;
// recalculate the price
purchased[i].cnt =
0; // reset the counter

$(
'#table_'+id).remove(); // remove it from the cart
update_total();
// update the total price counter on the page
}
function change(id) // evoked when we change the number of products via the select area{
var i=findpos(id);

totalprice+=(
parseInt($('#'+id+'_cnt').val())-purchased[i].cnt)*purchased[i].price;

purchased[i].cnt=
parseInt($('#'+id+'_cnt').val());
update_total();
}
function update_total() // function that updates the total price div on the page{
if(totalprice)
{
$(
'#total').html('total: $'+totalprice); // if we've bought somehitng, show the total price div and the purchase button
$(
'a.button').css('display','block');
}
else // hide them
{
$(
'#total').html('');
$(
'a.button').hide();
}
}





There are a few places in this code, where we use an id for pointing to a product. The id is a unique identifier, that is assigned by the MySQL database once we insert a new item.

It is passed by the AJAX requests and we need to translate it to the index position of our products array in order to use it, which is the purpose of the findpos() function.



With this our shopping cart is complete!




Conclusion




Today we made a functional AJAX driven shopping cart. You are free to download the code and modify it any way you wish. You can build upon it and even turn it into a full fledged online shop.













Comments

Popular posts from this blog

Bouncy Content Filter for big Website

This space-saving content filter allows the users to switch from one category to the other in a fancy way! Each click fires the rotation of the gallery images, revealing the items belonging to the selected category. Content filters  are particularly useful for big websites, where each pixel counts. Lets say you are showing the “ last products ” of your e-commerce . How about giving the users the option to switch to the “most popular” products without a page refresh? A good solution could be to hide the “most popular” items right behind the “last products”, then use the power of CSS3 3D Transforms to rotate the items when the user switches from one option to the other. The bounce effect is optional, but you get the idea! The rotation won’t work on older browsers like IE9, but the experience won’t be broken – just a display on/off with no transitions. Lets dive into the code! Creating the structure We wrapped the filter into a <nav> element. The filter structur...

Side Team Member Biography Resource

Use this team member biography resource to insert extended descriptions of your team members, with no need of dedicated pages or modal windows. Let the user meet your team and trust your company! Sometimes a picture and a role are not enough to completely describe a team member; you need a more detailed description to make your team “real”! But this requires space… and you can gain it using CSS3 transformations . Just give a look at the smart solution found by Aquatilis : the description enters from the side, just like mobile application behaviour, with no need of page reload. Creating the structure We created a #cd-team section containing our team members preview: <section id="cd-team" class="cd-section"> <div class="cd-container"> <h2>Our team</h2> <ul> <li> <a href="#0" data-type="member-1"> <figure><!-- .... --></figure> <div class=...

Pricing Table-Cross Reference Table for Website

Pricing Table-Cross Reference Table for Website.Tables are indispensable parts of web designs. They let you visually organise tabular content, distributing it on rows and columns. Although they are quite easy to design and code for large screens, things get more complicated on smaller devices. Whether it’s a subscription plan or a checkout process, you must deal with tables in your projects. And you must deal with responsiveness too. I’ve noticed some websites just cut off some columns to make their tables fits on a phone, but this solution doesn’t work in most cases (at least not if you need 5+ columns). I found this good example of a responsive table which inspired this resource: the list of features gets fixed on a side, allowing the user to horizontally scroll through the columns. Nice! Now why didn’t I use the HTML table structure , and instead went with unordered lists? It was difficult for me to make this resource responsive using proper table semantics (maybe an...