Total Cart Weight in Cart does not auto update when item quantities are changed.

Solved
DeborahLi
Tourist
4 0 1

Hi, I'm using the Narrative theme and added the following code to my cart-template.liquid file:

Total Weight: {{ cart.total_weight | weight_with_unit }}

It shows up nicely. But when I try changing the item quantities in the cart, the total weight does not update accordingly. Only when I refresh the page, then I see the new weight. How do I make the weight auto update please?

Thanks.

0 Likes
Propero
Shopify Partner
787 90 135

@DeborahLi ,

You need to update using Ajax, changes will be required to make in theme.js. 

- Was my reply helpful? Click Like or Click Accept as Solution
To hire: email us at shopify@propero.in
checkout our app https://apps.shopify.com/picamaze
0 Likes
EnriqueM
Excursionist
10 4 4

Hi, maybe you can do it this way:

 

On cart.template, add this above the ".cart-subtotal" div:

<div class="cart-total-weight">
  <span class="cart-weight__title h4">Total weight</span>
  <span class="cart-subtotal__price " data-cart-weight>{{ cart.total_weight | weight_with_unit }}</span>
</div>

 I have reused the ".cart-subtotal__price" because it's styling, you cant create a new class if you want.

 

Then make this changes on theme.js:

1. Append "cartWeight: '[data-cart-weight]'" to selectors$8, so you have:

var selectors$8 = {
  ajaxCart: '.cart-drawer',
  itemList: '[data-cart-item-list]',
  item: '[data-cart-item]',
  itemId: '[data-cart-item-id]',
  itemHref: '[data-cart-item-href]',
  itemImage: '[data-cart-item-image]',
  itemBackgroundImage: '[data-cart-item-background-image]',
  itemTitle: '[data-cart-item-title]',
  itemVariantTitle: '[data-cart-item-variant-title]',
  itemPropertyList: '[data-cart-item-property-list]',
  itemProperty: '[data-cart-item-property]',
  itemDiscountList: '[data-cart-item-discount-list]',
  itemDiscount: '[data-cart-item-discount]',
  itemDiscountTitle: '[data-cart-item-discount-title]',
  itemDiscountAmount: '[data-cart-item-discount-amount]',
  itemLabelQuantity: '[data-cart-item-label-quantity]',
  itemInputQuantity: '[data-cart-item-input-quantity]',
  itemDelete: '[data-cart-item-delete]',
  itemPriceContainer: '[data-cart-item-price-container]',
  itemLinePriceContainer: '[data-cart-item-line-price-container]',
  itemMessage: '[data-item-message]',
  cartDiscountContainer: '[data-cart-discount-container]',
  cartDiscount: '[data-cart-discount]',
  cartDiscountTitle: '[data-cart-discount-title]',
  cartDiscountAmount: '[data-cart-discount-amount]',
  cartNoteContainer: '[data-cart-note-container]',
  cartNoteInput: '[data-cart-note]',
  cartMessage: '[data-cart-message]',
  cartSubtotal: '[data-cart-subtotal]',
  cartSubmit: '[data-cart-submit]',
  cartWeight: '[data-cart-weight]'
};

 

And then add this snippet of code inside "_createCart", just before "return $container":

var weightUnit = $(selectors$8.cartWeight, $container).text().split(" ")[1];
$(selectors$8.cartWeight, $container).html(
    parseFloat(state.total_weight / 1000).toFixed(1) + " " + weightUnit
);

 

Should work this way. Remember that theme.js is unminified, so to see this changes you must change theme.liquid and reference "theme.js" instead of "theme.min.js". You also should minify theme.js before going live.

0 Likes
DeborahLi
Tourist
4 0 1

@EnriqueM, I followed your instructions and changed the code according. But it didn't work.

Am not sure what you mean by your last paragraph "Remember that theme.js is unminified, so to see this changes you must change theme.liquid and reference "theme.js" instead of "theme.min.js". You also should minify theme.js before going live."

Do you mean change the file name? won't it affect the other files?

Sorry if I'm being a noob. Appreciate your patience and help. Thanks.

0 Likes
DeborahLi
Tourist
4 0 1

@Propero, how I do that please? thanks tons.

EnriqueM
Excursionist
10 4 4

@DeborahLi You need to change this on theme.liquid

<script src="{{ 'theme.min.js' | asset_url }}" defer="defer"></script>

For this:

<script src="{{ 'theme.js' | asset_url }}" defer="defer"></script>

theme.js (where you made the changes) is the "readable" version of theme.min.js, but keeping unminified code on live websites it's not the best practice. It should work anyway.

I will try to put a theme-agnostic solution that doesn't modify existent js here on my next break

0 Likes
EnriqueM
Excursionist
10 4 4

This is an accepted solution.

Hi again. This is a more universal approach, so it should work on almost any theme (put it on custom.js or equivalent):

 

var s_ajaxListener = new Object();
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;

XMLHttpRequest.prototype.open = function(a,b) {
  if (!a) var a='';

  if (!b) var b='';
  s_ajaxListener.tempOpen.apply(this, arguments);
  s_ajaxListener.method = a;  
  s_ajaxListener.url = b;
  if (a.toLowerCase() == 'get') {
    s_ajaxListener.data = b.split('?');
    s_ajaxListener.data = s_ajaxListener.data[1];
  }
}

XMLHttpRequest.prototype.send = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempSend.apply(this, arguments);
  if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
  s_ajaxListener.callback();
}

s_ajaxListener.callback = function () {     
  if (this.url.indexOf('/cart/change.js') != -1){         
    setTimeout(function(){ 
      var xhttp = new XMLHttpRequest();
      var elem = document.querySelector('[data-cart-weight]');
      var unit = elem.innerText.split(" ")[1]
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          elem.textContent = parseFloat(JSON.parse(this.response).total_weight / 1000).toFixed(1) + " " + unit
        }
      };
      xhttp.open("GET", "/cart.js", true);
      xhttp.send();
    }, 500);
  }
}

 

This also needs this code below on cart-template:

 

<div class="cart-total-weight">
  <span class="cart-weight__title h4">Total weight</span>
  <span class="cart-subtotal__price " data-cart-weight>{{ cart.total_weight | weight_with_unit }}</span>
</div>

 

It has a 500 ms delay, because im not using callbacks included in theme.js so it can work anywhere.

DeborahLi
Tourist
4 0 1

@EnriqueM, it worked! thanks so much!!!

0 Likes
Huda-HN
Tourist
19 0 1

@EnriqueM 
Dear

I tried to do it , but I missed up everything 

the cart now not working.

can you please help to go back to the old version or help me to update it 

0 Likes
SandyMandy
New Member
1 0 0

Hi,

So thanks to you @EnriqueM ', your universal solution, it kind of worked, but it give me a weird "Undefined" whenever I change the actual quantity.

What I did was based on your solution was

  1. Added your universal js into the end of my theme.js  (sorry, didn't know how to use the custom.js as you recommended)
  2. Added the desired HTML into my cart-template.liquid as below 

 

 

          <div class="cart-total-weight">
  <span class="cart-weight__title h4">Total</span>
  <span class="cart-weight__title h4" data-cart-weight>{{ cart.total_weight | round }}</span>
</div>​

 

 

  • And with that, on the first view of the cart, I get exactly what I needed in the value.    SandyMandy_0-1619248443730.png
  • BUT, whenever I change the item quantity, in this case I added 1 more product so it should be 4400 of weight, it shows as below

SandyMandy_1-1619248464978.png

So for whatever reason, suddenly the units are divided by 1000, and I get this UNDEFINED text right next to it. I believe the root cause is the same, but would you be able to guide me how to fix this?  As a side note, I do not really use the weight variable for weight, but another measurement I need, so do not want to show the units of kg and lb.

Thank you for  looking into this.

 

0 Likes