LocalStorage keeps bringing back removed values
I am using local storage API to store items in the cart, but i am having a problem with it. At first when i add an item into it, it works normally and also when i remove the item is works normally. but when i try to add one item to the cart, the localStorage brings back all the removed items.
There are two function below,
AddToCart()
– to add item from the home and single product page,removeFromCart()
– remove item from the cart.
function AddToCart(){ // Home page var data = JSON.parse(localStorage.getItem('zysod_cart')) $('.addcart').on('click', function(){ var $this = $(this).closest('.single-product-content') var productId = parseInt($this.attr('data-product-id')) var productName = $this.find('.product-title').text() var productImg = $this.attr('data-product-src') var productPrice = $this.find('.product-price .regular-price').text() var found = data.products.some(function(el){ return parseInt(el.id) === productId }) if (!found) { data.items = parseInt(data.items) + 1; data.products.push({ id: productId, name: productName, quantity: 1, image: productImg, price: productPrice }); var total = 0 for(var item in data.products){ total += (data.products[item].price === 'Price not available'? 0 : parseInt(data.products[item].price.replace(',','').slice(1))) * data.products[item].quantity } data.total = total localStorage.setItem('zysod_cart', JSON.stringify(data)); UpdateCart() } else { for (var i = 0; i < data.products.length; i++) { if (parseInt(data.products[i].id) === productId) { data.products[i].quantity = parseInt(data.products[i].quantity + 1); var total =0; for(var item in data.products){ total += (data.products[item].price === 'Price not available'? 0 : parseInt(data.products[item].price.replace(',','').slice(1))) * data.products[item].quantity } data.total = total localStorage.setItem('zysod_cart', JSON.stringify(data)); UpdateCart() } } } }) // Single Product Page $('.h-addcart').on('click',function(){ var $this = $(this).closest('.single-product') var productId = parseInt($this.attr('data-product-id')) var productName = $this.find('.product-title').text() var productImg = $this.attr('data-product-src') var productPrice = $this.find('.product-price .price-sale').text() var found = data.products.some(function(el){ return parseInt(el.id) === productId }) if (!found) { data.items = parseInt(data.items) + 1; data.products.push({ id: productId, name: productName, quantity: 1, image: productImg, price: productPrice }); var total =0; for(var item in data.products){ total += (data.products[item].price === 'Price not available'? 0 : parseInt(data.products[item].price.replace(',','').slice(1))) * data.products[item].quantity } data.total = total localStorage.setItem('zysod_cart', JSON.stringify(data)); } else { for (var i = 0; i < data.products.length; i++) { if (parseInt(data.products[i].id) === productId) { data.products[i].quantity = parseInt(data.products[i].quantity + 1); var total =0; for(var item in data.products){ total += (data.products[item].price === 'Price not available'? 0 : parseInt(data.products[item].price.replace(',','').slice(1))) * data.products[item].quantity } data.total = total localStorage.setItem('zysod_cart', JSON.stringify(data)); } } } }) } function removeFromCart(){ $(document).on('click','.dropcart__product-remove',function(){ var $this = $(this).closest('.dropcart__product') var productId = parseInt($this.attr('data-product-id')) var data = JSON.parse(localStorage.getItem('zysod_cart')); data.products = $.grep(data.products, function (e) { if(e.id == productId){ data.total-= e.price === 'Price not available'? parseInt(0): (parseInt(e.price.replace(',','').slice(1))*parseInt(e.quantity)) } return e.id != productId; }); data.items = data.products.length localStorage.setItem('zysod_cart', JSON.stringify(data)); }) }
This is because of the data
is read once when AddToCart
is called.
function AddToCart() { var data = JSON.parse(localStorage.getItem('zysod_cart')) // ... }
ℹ️ This is because of closures which refer to the top most
data
variable in the upper scope. Read more about closures in Mozilla Developer Network article.
If you want to solve this you should read data
from the localStorage each time you change the data, like you do in removeFromCart()
inside of each click
event handler:
function removeFromCart(){ $(document).on('click','.dropcart__product-remove',function(){ var $this = $(this).closest('.dropcart__product') var productId = parseInt($this.attr('data-product-id')) var data = JSON.parse(localStorage.getItem('zysod_cart')); // ... }) }
⚠️ You should be noted that several tabs can update the localStorage simultaneously what can cause conflicts. To avoid this it is recommended to use SharedWorker to synchronise different tabs.
Advice
I’d suggest to make your code modular aand supportable, if this is required. You can separate event handling and localStorage manipulation, like this:
class Storage { constructor(name, data) { this.name = name if (data) { this.save(data) } else { if (name in localStorage) { this.data = JSON.parse(localStorage.getItem(name)) } else { this.save({}) } } } save(data) { this.data = data this.updateStorage() } updateStorage() { localStorage.setItem(this.name, JSON.stringify(this.data)) } } const storage = new Storage('zysod_cart') function bindAddToCart(storage) { $('#addButton').on('click', function () { // Copy data const data = {...storage.data} // Add cart logic here ... // Save changes storage.save(data) }) } function bindRemoveFromCard(storage) { $('#removeButton').on('click', function () { // Copy data const data = {...storage.data} // Remove card logic here ... // Save changes storage.save(data) }) }
But note that there should be only one instance of Storage
with the name
value of zysod_cart
on the page.