0

I'm still so new to Magento. So this article about update the shopping cart by Ajax. https://www.magemonkeys.com/magento-2-update-cart-using-ajax-when-quantity-change/. I'm wondering how this all code works?

I understand creating a new module can overwrite the existing Magento code. I don't understand how this new module works. How does cartQtyUpdate.js call the function to load subtotal and order total?

2
  • What you are looking for? Aug 17, 2020 at 18:01
  • I'm just wondering how the code works, how does cartQtyUpdate.js could call the function to load the new subtotal and order total? @DhirenVasoya Aug 17, 2020 at 18:13

1 Answer 1

0

First:

  • In step 5 there is a mistake. Depending on "load" event inside require isn't correct.
  • It also uses default GET method in ajax request and because of it later there is a manual call of method to reload customerData 'cart' section. If we would use POST method we wouldn't have to reload 'cart' section this way.

But "How it load subtotal order and order total?"

Magento 2 in many places uses KnockoutJS to render and update UI elements. In short we can create knockout observables in javascript and if we updated its value it will automatically update on our page.

I recommend to look for some articles about KnockoutJS and how it works in Magento2. It's also important to understand how RequireJs works as it will help you understand Magento2 JS system.

Here I will show you how it works on example provided by you. I hope you will understand little more. But perhaps you will find how much more you need to learn. But remember. Step by step you can understand it. It can just take some time.

When using chrome knockoutjs extensions you can see that subtotal element is rendered via javscript file: Magento_Tax/js/view/checkout/summary/subtotal (js file).

https://i.gyazo.com/5902c02d16e0bcd7c4f462b78349630b.png

It uses template: "Magento_Tax/checkout/summary/subtotal" (html file located in vendor/magento/module-tax/view/frontend/web/template/checkout/summary/subtotal.html)

We see there:

<span class="price" data-bind="text: getValue(), attr: {'data-th': excludingTaxMessage}"></span>

So data-bind let us declare bindings. Here we have text and attr bindings. IN short text binding will put value returned by getValue() inside this span as a "text".

Let's check now what returns this method from subtotal.js file mentioned before.

getValue: function () {
  var price = 0;

  if (this.totals()) {
    price = this.totals().subtotal;
  }

  return this.getFormattedPrice(price);
}

It returns a price. Most important here is this.totals()

if we look above we see:

define([
    'Magento_Checkout/js/view/summary/abstract-total',
    'Magento_Checkout/js/model/quote'
], function (Component, quote) {
    'use strict';

    var displaySubtotalMode = window.checkoutConfig.reviewTotalsDisplayMode;

    return Component.extend({
        defaults: {
            displaySubtotalMode: displaySubtotalMode,
            template: 'Magento_Tax/checkout/summary/subtotal'
        },
        totals: quote.getTotals(),

We see quote.getTotals(). Where it comes from? It comes from dependency defined at the top. It means that "quote" variable will be represented by object returned by Magento_Checkout/js/model/quote

In quote.js we can find things like:

totals = ko.observable(totalsData),
...
return {
    totals: totals,
 
    /**
     *
     * @return {*}
     */
    getTotals: function () {
        return totals;
    },

    /**
     * @param {Object} data
     */
    setTotals: function (data) {
        data = proceedTotalsData(data);
        totals(data);
        this.setCollectedTotals('subtotal_with_discount', parseFloat(data['subtotal_with_discount']));
    },

Here we see that first total are declared as knockout observable (so if we change its value it can be automatically update in UI - if it is used there or we could do few other things).

Then this observable is set as reference to totals property of object that is returned by this. We also return here some methods like getTotals, setTotals etc.

Now what we need to do to update subtotals/totals in our UI? We just need to call setTotal method using our quote module (quote.js)/

And this is what getTotalsActions method called in code below does.

In cartQtyUpdate.js you see it is called in success callback

success: function (res) {
  ...
  /* Totals summary reloading */
  var deferred = $.Deferred();
  getTotalsAction([], deferred);
}

To see what is getTotalsAction we need go to the top of this file.

define([
    'jquery',
    'Magento_Checkout/js/action/get-totals',
    'Magento_Customer/js/customer-data'
], function ($, getTotalsAction, customerData) {

getTotalsAction is what Magento_Checkout/js/action/get-totals returns.

Let's see the main part of this file:

return function (callbacks, deferred) {
  deferred = deferred || $.Deferred();
  totals.isLoading(true);

  return storage.get(
    resourceUrlManager.getUrlForCartTotals(quote),
    false
  ).done(function (response) {
    var proceed = true;

    totals.isLoading(false);

    if (callbacks.length > 0) {
      $.each(callbacks, function (index, callback) {
        proceed = proceed && callback();
      });
    }

    if (proceed) {
      quote.setTotals(response);
      deferred.resolve();
    }
  }).error(function (response) {
    totals.isLoading(false);
    deferred.reject();
    errorProcessor.process(response);
  }).always(function () {
    totals.isLoading(false);
  });
};

Here we have another AJAX request (we use here get() method from lib/mage/web/storage.js). We set "loader" for totals, get updated value and set totals using setTotals method from quote.js

Then our knockout observable totals is updated and in the end our UI. This example is little complicated because we see how many files are used here and connected to each other.

So for this part I recommend reading more about knockoutjs, requirejs as well how javascript systems works in magento2 (Magento 2 dev docs, Alan Storm and other resources).

How cart form (main table with items and qty) is updated?

From provided code

   success: function (res) {
       var parsedResponse = $.parseHTML(res);
       var result = $(parsedResponse).find("#form-validate");
       var sections = ['cart'];

      $("#form-validate").replaceWith(result);

we see it parse the result (html page) and query only form-validate part and replace the current one cart form with update version using jquery method replaceWith.

Few words about how "minicart" is updated?

I won't answer this question completely as I already wrote quite a few things. But after adding product success callback is executed we see customerData.reload(sections, true) where sections = 'cart'.

This updates minicart. Here we could use "POST" method instead of "GET" and we wouldn't have to call customerData.reqload... as Magento2 can automatically update specific sections like "cart" if there is any "POST|PUT|DELETE" requests for specified urls. But I think we would need add those url related to update cart to section.xml to make it work.

How exactly this works? Please read more about this in links provided by me below. As I believe it's already quite nice explained in those resources.

5
  • Thank you for your explanation! how does it reload the subtotal for each item in the shopping cart? @JanuszJanczy Aug 18, 2020 at 17:21
  • in line 15-19. Code takes response and use only form part and replace it using jquery replaceWith method Aug 18, 2020 at 17:32
  • sorry, in what file? Aug 18, 2020 at 18:05
  • from the link you posted. In cartQtyUpdate.js Aug 18, 2020 at 19:34
  • And sorry, one more question, how does the module recognize that we update the shopping cart qty and not the other qty (for example, minicart qty). Because this part still confuses me. Aug 20, 2020 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.