HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

localStorage functions for website shopping cart

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
websitelocalstoragecartforfunctionsshopping

Problem

As part of a larger web app we are producing, I was asked to help build functionality to tie a page's shopping cart into localStorage for persistence. What follows are the three functions that I wrote that produce a JSON representation of the cart, and stores it in LS.

As far as I can tell, it all works great. I'm curious if I'm missing any best practices, or if I've done something that could prove problematic at scale, etc. Maybe there are just some general improvements I could make or something you would do differently. I just want to make sure I'm always working towards producing the best code I can, and unfortunately I don't have the resources on my team to do internal code review.

Note that all the console logging is mostly there for debugging, and almost all of it will be removed before the code itself goes live. I'm particularly interested if my for-loop approach is the best possible solution for searching and updating existing JSON items.

```
var cartItems;
var MyApp = {};

// On load, look for an existing cart to preload
MyApp.getCart = function() {
// Check for localStorage
if(localStorage) {
if(localStorage['myapp.cart'] != null) {
// Get the cart
cartItems = JSON.parse(localStorage['myapp.cart']);
checkoutCounter = cartItems.count;
// Update the button counter value
counterSpan.text(checkoutCounter);
// External function to enable the button
MyApp.theCounter();
}
} else {
console.log('localStorage not detected, cannot get cart.');
}
};

// Add an item to the localStorage cart
MyApp.saveToCart = function(role) {
if(localStorage) {
console.log('localStorage detected. Processing cart item: '+role);
// Create a new cart array object if there isn't one
if(cartItems == null) {
console.log('Cart is empty, preparing new cart array');
cartItems = {
'count': '1',

Solution

You should write a thin wrapper around localStorage so that you don't have to constantly ask if (localStorage) every time you want to use it. You can also do that test once, and if it doesn't exist, stub it out with a simple {}:

if (!localStorage) {
  console.log("LocaleStorage is not supported, data will not be persisted")

  // Let the program use a stub object to proceed
  localStorage = {};
  localStorage.prototype.removeItem = function(key) {
    this[key] = null;
  }
}

store = {
  read: function(key) {
    if (localStorage[key])
      return JSON.parse(localStorage[key])

    return null;
  },

  write: function(key, value) {
    localStorage[key] = JSON.stringify(value)
  },

  clear: function(key) {
    localStorage.removeItem(key);
  }
}


Now your methods look much simpler:

// On load, look for an existing cart to preload
MyApp.getCart = function() {
  // Get the cart
  cartItems = store.read("myapp.cart")
  checkoutCounter = cartItems.count;
  // Update the button counter value
  counterSpan.text(checkoutCounter);
  // External function to enable the button
  MyApp.theCounter();
};


There's a ton of cleanup to be done by making this object oriented. You could be creating a ShoppingCart class which has save/load/addItem/removeItem/etc, and then creating a global instance called myCart. It would be much, much cleaner than a bunch of global functions.

By which I mean:

ShoppingCart = function(name) {
  this.name = name;
  this.items = store.read(name)
}

ShoppingCart.prototype = {
  save: function () {
    store.write(this.name, this.items)
  },

  addItem: function (role) {
    if (this.items[role])
      this.items[role] += 1;
    else
      this.items[role] = 1;

    this.save()
  },

  removeItem: function(role) {
    if (this.items[role])
      this.items[role] -= 1;

    if (this.items[role] == 0)
      delete this.items[role];

    this.save()
  }

}

var myCart = new ShoppingCart("myapp.cart");

Code Snippets

if (!localStorage) {
  console.log("LocaleStorage is not supported, data will not be persisted")

  // Let the program use a stub object to proceed
  localStorage = {};
  localStorage.prototype.removeItem = function(key) {
    this[key] = null;
  }
}

store = {
  read: function(key) {
    if (localStorage[key])
      return JSON.parse(localStorage[key])

    return null;
  },

  write: function(key, value) {
    localStorage[key] = JSON.stringify(value)
  },

  clear: function(key) {
    localStorage.removeItem(key);
  }
}
// On load, look for an existing cart to preload
MyApp.getCart = function() {
  // Get the cart
  cartItems = store.read("myapp.cart")
  checkoutCounter = cartItems.count;
  // Update the button counter value
  counterSpan.text(checkoutCounter);
  // External function to enable the button
  MyApp.theCounter();
};
ShoppingCart = function(name) {
  this.name = name;
  this.items = store.read(name)
}

ShoppingCart.prototype = {
  save: function () {
    store.write(this.name, this.items)
  },


  addItem: function (role) {
    if (this.items[role])
      this.items[role] += 1;
    else
      this.items[role] = 1;

    this.save()
  },

  removeItem: function(role) {
    if (this.items[role])
      this.items[role] -= 1;

    if (this.items[role] == 0)
      delete this.items[role];

    this.save()
  }

}

var myCart = new ShoppingCart("myapp.cart");

Context

StackExchange Code Review Q#22711, answer score: 4

Revisions (0)

No revisions yet.