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));                      }) } 
Add Comment
1 Answer(s)

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.

Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.