Magento2 – Update Cart Total Dynamically When Promo Code Applied

cartcheckoutcouponknockoutjsmagento2

I have changed my checkout/cart/ page promo code to ajax call so that it doesn't get reloaded, while on the success of that ajax call, I have to update the total price summary dynamically without reloading.

How to achieve that.

enter image description here

Need to update this(price summary) as soon as user apply the promo code, I am using ajax instead of reloading the page as it was happening earlier.

I referred some links,

define([
'jquery',
'Magento_Checkout/js/model/cart/totals-processor/default',
'Magento_Checkout/js/model/quote',
'OtherDependencies'
], function ($,totalsProvider, quote){
  'use strict';
  //Your code here
  totalsProvider.estimateTotals(quote.shippingAddress());
});

How this code supposed to work as i dont have any shippingAddress here.

It just promo code and have to update the subtotal and order total with promo amount applied.

Best Answer

You can use an action like this:

require(
    [
        'Magento_Checkout/js/model/cart/cache',
        'Magento_Checkout/js/model/cart/totals-processor/default',
        'Magento_Checkout/js/model/quote'
    ],
    function (cartCache, totalsProcessor, quote) {
        cartCache.clear('cartVersion');
        totalsProcessor.estimateTotals(quote.shippingAddress());
    }
);

It will update the cart totals from the cart page using default shipping address from the quote. If there was no address it is another issue.

I tested it in the browser console this way:

require(
    [
        'Magento_Checkout/js/model/cart/cache',
        'Magento_Checkout/js/model/cart/totals-processor/default',
        'Magento_Checkout/js/model/quote'
    ],
    function (cartCache, totalsProcessor, quote) {
        var form = jQuery('#discount-coupon-form');
        jQuery.ajax(
            {
                type: "POST",
                url: form.attr('action'),
                data: form.serialize(),
                success: function (response) {
                    console.log(response);
                    cartCache.clear('cartVersion');
                    totalsProcessor.estimateTotals(quote.shippingAddress());
                }
            }
        );
    }
)();

and all works fine on Magento 2.3.1 for not logged in customer.

Result

PS: I know that my answer is not a complete, but maybe this information will be useful for you.


Update:

Here is simplified example:

Add our component which submit coupon code using AJAX and update cart totals:

app/code/Vendor/Module/view/frontend/requirejs-config.js

var config = {
    map: {
        '*': {
            submitCoupon: 'Vendor_Module/js/submitCoupon'
        }
    }
};

Create js file with action (it is simplified, you need to write own logic):

app/code/Vendor/Module/view/frontend/web/js/submitCoupon.js

define([
    'jquery',
    'Magento_Checkout/js/model/cart/cache',
    'Magento_Checkout/js/model/cart/totals-processor/default',
    'Magento_Checkout/js/model/quote'
], function ($, cartCache, totalsProcessor, quote) {
    'use strict';

    console.log('Submit coupon loaded');

    var form = $('#discount-coupon-form');

    $('#submit_coupon').on('click', function () {
        $.ajax(
            {
                type: "POST",
                url: form.attr('action'),
                data: form.serialize(),
                success: function (response) {
                    console.log(response);
                    cartCache.clear('cartVersion');
                    totalsProcessor.estimateTotals(quote.shippingAddress());
                }
            }
        );
    });
});

Add simple block with template into layout for the cart page (simplified, you need to write own):

app/code/Vendor/Module/view/frontend/layout/checkout_cart_index.xml

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template" name="submit_coupon" before="-" template="Vendor_Module::coupon.phtml"/>
        </referenceContainer>
    </body>
</page>

Create template (simplified too, write your own with desired design):

app/code/Vendor/Module/view/frontend/templates/coupon.phtml

<div id="submit_coupon">
    <?= __('Submit Coupon'); ?>
</div>
<script type="text/x-magento-init">
    {
        "#submit_coupon": {
            "submitCoupon": {}
        }
    }
</script>

As a result after clean cache and redeploy static content you will see the <div> having a text Submit Coupon. When you have press it the coupon code entered in the default input will be sent to a server and after it will be processed the cart totals will be updated.

Example of how it works

PPS: As I said, it is just a very simplified scheme which serves to understand "how it will work". For your purposes you need to write something more complicated and well designed.