Shopping cart: Cookies only holding 2 - 5 items
cookies, javascript, session-cookies, shopping-cart, variables
Solution
In my opinion the problem is related to the 4K cookie size limit. Your `shopppingcart` code is trying to store all the items data in a `simpleCart` cookie, but when such data gets bigger than 4K the items are not stored into the cookie, even if they're showed in the cart, therefore when the page is reloaded those items disappear. Consider for example the site http://shoppingcart-bthub.blogspot.in/, and specifically the HTML markup for the "Sony VAIO laptop" item:
<table border="1" style="width: 660px;">
<tbody>
<tr>
<th class="item_thumb" id="thumb" width="45%"><img border="0" src="http://3.bp.blogspot.com/-LcQD--Bb_YE/TeDI44AmUsI/AAAAAAAACBw/K4IJZE2CpMY/s1600/sony+vaio.JPG"></th>
<td>
<input class="item_add" type="button" value="Add to Cart" id="s1">
</td>
</tr>
<tr>
<th><b>Item Name</b></th>
<td class="item_name">Sony VPCEE42FX 15.5" 2.30GHz 500GB VAIO Laptop</td>
</tr>
<tr>
<th><b>Price</b></th>
<td class="item_price">$610.00</td>
</tr>
<tr>
<th><b>Description</b></th>
<td class="item_Description">
The VPCEE42FX is big enough to be useful, but small
enough to be portable. With 500GB of hard drive space, youll have to work hard
to fill up the memory. The 15.5 HD resolution screen and AMD Mobility Radeon HD
graphics card ensure that youll see crisp, fast action, even when youre watching
DVDs on the DVD drive. And at under six pounds, the laptop is easy to pack up
and haul with you.
</td>
</tr>
<tr>
<th><b>Available Stock</b></th>
<td>2 more available</td>
</tr>
</tbody>
</table>
When this product is added to the cart, the `simpleCart` cookie will contain the following string:
id=c10||thumb=%3Cimg%20border%3D%220%22%20src%3D%22http%3A//3.bp.blogspot.com/-LcQD--Bb_YE/TeDI44AmUsI/AAAAAAAACBw/K4IJZE2CpMY/s1600/sony+vaio.JPG%22%3E%0A||name=Sony%20VPCEE42FX%2015.5%22%202.30GHz%20500GB%20VAIO%20Laptop||price=610||description=The%20VPCEE42FX%20is%20big%20enough%20to%20be%20useful%2C%20but%20small%20enough%20to%20be%20%0Aportable.%20With%20500GB%20of%20hard%20drive%20space%2C%20youll%20have%20to%20work%20hard%20to%20%0Afill%20up%20the%20memory.%20The%2015.5%20HD%20resolution%20screen%20and%20AMD%20Mobility%20%0ARadeon%20HD%20graphics%20card%20ensure%20that%20youll%20see%20crisp%2C%20fast%20action%2C%20even%20%0Awhen%20youre%20watching%20DVDs%20on%20the%20DVD%20drive.%20And%20at%20under%20six%20pounds%2C%20the%20%0Alaptop%20is%20easy%20to%20pack%20up%20and%20haul%20with%20you.||quantity=1
As you can see, it seems that all the `<td>` elements with a class name starting with `item_` are stored in the cookie. Chrome Developer's Tools shows a size of 828 bytes for this cookie. Therefore the number of the items that can be added to the cart is variable and depends by the length of each item data (name, description, etc.). So, what can you do to avoid this problem?
- Reduce the item HTML markup to the minimum, for example by removing the `item_thumb` and `item_Description` elements.
- Modify the `addToCart` method in the `simplecart.js` code to reduce the lenght of the cookie by storing less information (see below for details).
- Modify the `createCookie`, `readCookie` and `eraseCookie` functions in the `simplecart.js` code to use local storage instead of a cookie to store item data (have a look at this page for a code sample, or below for another example).
For example, to avoid the storing of the "thumb" and "Description" item fields in the cookie, you could modify the `addToCart` method as follows:
ShelfItem.prototype.addToCart = function () {
var outStrings = [],valueString;
for( var field in this ){
if( typeof( this[field] ) != "function" && field != "id" ){
valueString = "";
//console.log(field);
switch(field){
case "price":
if( this[field].value ){
valueString = this[field].value;
} else if( this[field].innerHTML ) {
valueString = this[field].innerHTML;
}
/* remove all characters from price except digits and a period */
valueString = valueString.replace( /[^(\d|\.)]*/gi , "" );
valueString = valueString.replace( /,*/ , "" );
break;
case "image":
valueString = this[field].src;
break;
case "thumb":
case "Description":
case "description":
/* don't store "thumb" and "description" in the cookie */
break;
default:
if( this[field].value ){
valueString = this[field].value;
} else if( this[field].innerHTML ) {
valueString = this[field].innerHTML;
} else if( this[field].src ){
valueString = this[field].src;
} else {
valueString = this[field];
}
break;
}
outStrings.push( field + "=" + valueString );
}
}
}
A much better approach would be to use `localStorage` if the browser supports it, otherwise use cookies as a fallback:
function supports_html5_storage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
function createCookie(name,value,days) {
if (supports_html5_storage()) {
if (value == '') {
eraseCookie(name);
} else {
window.localStorage.setItem(name, JSON.stringify(value));
}
} else {
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) {
if (supports_html5_storage()) {
return window.localStorage.getItem(name);
} else {
var ca = document.cookie.split(';');
var nameEQ = name + "=";
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) {
if (supports_html5_storage()) {
window.localStorage.removeItem(name);
} else {
createCookie(name,"",-1);
}
}
When using `localStorage` we can also store the `thumb` and `description` fields without problems (since we have 5 Mb of space), therefore we can further modify the `ShelfItem.prototype.addToCart` function this way:
...
case "thumb":
case "Description":
case "description":
if (!supports_html5_storage()) break;
...
Problem
This is likely an easy fix (easy +200 reputation), for someone who has javascript skills. Demo of problem: http://shoppingcart-bthub.blogspot.com/ Just add all the items to the cart and click refresh to see the problem with the cookies. Everything works correctly, except the part of the code that handles cookies for the items that get added to the shopping cart. For some reason, it only holds 2 -5 items, depending on the broswer: Google Chrome - only holds 2 items (all other items in shopping cart disappear after page reload) Firefox - 4 items total Safari - 4 Internet Exploer - 5 The javascript in the demo: http://shopppingcart.googlecode.com/files/simplecart.js The part of the javascript link above that is coded to handle cookies: ``` /*** data storage and retrival ****/ /* load cart from cookie */ me.load = function () { var me = this; /* initialize variables and items array */ me.items = {}; me.total = 0.00; me.quantity = 0; /* retrieve item data from cookie */ if( readCookie('simpleCart') ){ var data = unescape(readCookie('simpleCart')).split('++'); for(var x=0, xlen=data.length;x<xlen;x++){ var info = data[x].split('||'); var newItem = new CartItem(); if( newItem.parseValuesFromArray( info ) ){ newItem.checkQuantityAndPrice(); /* store the new item in the cart */ me.items[newItem.id] = newItem; } } } me.isLoaded = true; }; /* save cart to cookie */ me.save = function () { var dataString = ""; for( var item in this.items ){ dataString = dataString + "++" + this.items[item].print(); } createCookie('simpleCart', dataString.substring( 2 ), 30 ); }; ``` To test the full live code: For the complete live template with all the codes, open a free blog at blogger.com and download the XML template here to upload into blogger: http://www.bloggermint.com/2011/05/shopping-cart-blogger-template/ The free download is in the left-hand sidebar. Also follow the intructions on that page to get it woking in blogger.com