Magento2 | PWA | GraphQL

Update Shopping Cart items quantity with AJAX on Checkout/cart and Checkout Page. Display Alert before remove items from cart on Checkout/cart Page


In this post we wiil check how to Update Shopping Cart items quantity with AJAX on Checkout/cart and Checkout Page.

On checkout Page add + / - button on cart items and update qty with AJAX also update no. of items on cart summary by AJAX.

You can update checkout/cart items quantity seamlessly and see total price adjustments on the shopping cart page without having to click 'update to cart' button.

Display Alert before remove items from cart on Checkout/cart Page.

Let's start by creating custom module.

You can find complete module on Github at Magelearn_AjaxShoppingCartUpdate







Create folder inside app/code/Magelearn_AjaxShoppingCartUpdate

Add registration.php file in it:

<?php

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Magelearn_AjaxShoppingCartUpdate',
    __DIR__
);

Add composer.json file in it:

{
    "name": "magelearn/module-ajaxshoppingcartupdate",
    "description": "Update Shopping Cart items quantity with AJAX. You can update checkout/cart items quantity seamlessly and see total price adjustments on the shopping cart page without having to click 'update to cart' button.",
    "type": "magento2-module",
    "license": "OSL-3.0",
    "authors": [
        {
            "email": "info@mage2gen.com",
            "name": "Mage2Gen"
        },
        {
            "email": "vijaymrami@gmail.com",
            "name": "vijay rami"
        }
    ],
    "minimum-stability": "dev",
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magelearn\\AjaxShoppingCartUpdate\\": ""
        }
    }
}

Add etc/module.xml file in it:

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magelearn_AjaxShoppingCartUpdate" setup_version="0.0.1" >
    </module>
</config>

Now first we will check how to add qty +/- button on checkout cart page and add alert when click on Remove item button on checkout/cart page.

FIrst add app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/layout/checkout_cart_index.xml file.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.cart.form">
            <action method="setTemplate">
                <argument name="template" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/form.phtml</argument>
            </action>
        </referenceBlock>
    </body>
</page>

Also add app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/layout/checkout_cart_item_renderers.xml file.

<?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>
		<!-- override checkout cart item template -->
		<referenceBlock name="checkout.cart.form">
			<action method="setOverriddenTemplates">
				<argument xsi:type="array">
					<!-- list override templates -->
					<item name="default" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
					<item name="simple" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
					<item name="configurable" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
					<item name="bundle" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
					<item name="downloadable" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
					<item name="grouped" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
					<item name="virtual" xsi:type="string">Magelearn_AjaxShoppingCartUpdate::cart/item/default.phtml</item>
				</argument>
			</action>
		</referenceBlock>
	</body>
</page>

As per defined in above XML files we will add our phtml files and add code to update cart items with AJAX.

Copy file from vendor/magento/module-checkout/view/frontend/templates/cart/form.phtml and Add in app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/templates/cart/form.phtml file.

<?php /**  @var $block \Magento\Checkout\Block\Cart\Grid */ ?>
<?php $mergedCells = ($this->helper(Magento\Tax\Helper\Data::class)->displayCartBothPrices() ? 2 : 1); ?>
<?= $block->getChildHtml('form_before') ?>
<form action="<?= $block->escapeUrl($block->getUrl('checkout/cart/updatePost')) ?>"
          method="post"
          id="form-validate"
          data-mage-init='{"Magento_Checkout/js/action/update-shopping-cart":
              {"validationURL" : "<?= $block->escapeUrl($block->getUrl('checkout/cart/updateItemQty')) ?>",
              "updateCartActionContainer": "#update_cart_action_container"}
          }'
          class="form form-cart">
    <?= $block->getBlockHtml('formkey') ?>
    <div class="cart table-wrapper<?= $mergedCells == 2 ? ' detailed' : '' ?>">
        <?php if ($block->getPagerHtml()): ?>
            <div class="cart-products-toolbar cart-products-toolbar-top toolbar"
                 data-attribute="cart-products-toolbar-top"><?= $block->getPagerHtml() ?>
            </div>
        <?php endif ?>
        <table id="shopping-cart-table"
               class="cart items data table"
               data-mage-init='{"shoppingCart":{"emptyCartButton": ".action.clear",
               "updateCartActionContainer": "#update_cart_action_container"}}'>
            <caption class="table-caption"><?= $block->escapeHtml(__('Shopping Cart Items')) ?></caption>
            <thead>
                <tr>
                    <th class="col item" scope="col"><span><?= $block->escapeHtml(__('Item')) ?></span></th>
                    <th class="col price" scope="col"><span><?= $block->escapeHtml(__('Price')) ?></span></th>
                    <th class="col qty" scope="col"><span><?= $block->escapeHtml(__('Qty')) ?></span></th>
                    <th class="col subtotal" scope="col"><span><?= $block->escapeHtml(__('Subtotal')) ?></span></th>
                </tr>
            </thead>
            <?php foreach ($block->getItems() as $_item): ?>
                <?= $block->getItemHtml($_item) ?>
            <?php endforeach ?>
        </table>
        <?php if ($block->getPagerHtml()): ?>
            <div class="cart-products-toolbar cart-products-toolbar-bottom toolbar"
                 data-attribute="cart-products-toolbar-bottom"><?= $block->getPagerHtml() ?>
            </div>
        <?php endif ?>
    </div>
    <div class="cart main actions">
        <?php if ($block->getContinueShoppingUrl()): ?>
            <a class="action continue"
               href="<?= $block->escapeUrl($block->getContinueShoppingUrl()) ?>"
               title="<?= $block->escapeHtml(__('Continue Shopping')) ?>">
                <span><?= $block->escapeHtml(__('Continue Shopping')) ?></span>
            </a>
        <?php endif; ?>
        <?php if ($block->getViewModel()->isClearShoppingCartEnabled()): ?>
            <button type="button"
                    name="update_cart_action"
                    data-cart-empty=""
                    value="empty_cart"
                    title="<?= $block->escapeHtml(__('Clear Shopping Cart')) ?>"
                    class="action clear" id="empty_cart_button">
                <span><?= $block->escapeHtml(__('Clear Shopping Cart')) ?></span>
            </button>
        <?php endif ?>
        <button type="submit"
                name="update_cart_action"
                data-cart-item-update=""
                value="update_qty"
                title="<?= $block->escapeHtml(__('Update Shopping Cart')) ?>"
                class="action update">
            <span><?= $block->escapeHtml(__('Update Shopping Cart')) ?></span>
        </button>
        <input type="hidden" value="" id="update_cart_action_container" data-cart-item-update=""/>
    </div>
</form>
<?= $block->getChildHtml('checkout.cart.order.actions') ?>
<?= $block->getChildHtml('shopping.cart.table.after') ?>
<script type="text/javascript">
    require(['jquery', 'CartQtyUpdate'], function ($) {
    });
</script>
<script>
require([
    'jquery',
    'mage/translate',
    'Magento_Ui/js/modal/confirm',
    "mage/template",
], function ($, $t, confirm, mageTemplate) {
    $('.action-delete').click(function (e) {
        e.stopPropagation();
        var params11 = $(e.currentTarget).data('post');
        console.log(params11);
        confirm({
            title: $t("Remove item cart"),
            content: $t("Do you want remove this item of the cart?"),
            modalClass: "classModal",
            actions: {
                confirm: function () {
                    var params = $(e.currentTarget).data('post');
                    var formTemplate = '<form action="<%- data.action %>" method="post">'
                        + '<% _.each(data.data, function(value, index) { %>'
                        + '<input name="<%- index %>" value="<%- value %>">'
                        + '<% }) %></form>';
                    var formKeyInputSelector = 'input[name="form_key"]';

                    var formKey = $(formKeyInputSelector).val();
                    if (formKey) {
                        params.data.form_key = formKey;
                    }
                    $(mageTemplate(formTemplate, {
                        data: params
                    })).appendTo('body').hide().submit();
                }
            }
        });
    })
});
</script>

Copy file from vendor/magento/module-checkout/view/frontend/templates/cart/item/default.phtml file and Add in app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/templates/cart/item/default.phtml file.

<?php /** @var $block \Magento\Checkout\Block\Cart\Item\Renderer */
$_item = $block->getItem();
$product = $_item->getProduct();
$isVisibleProduct = $product->isVisibleInSiteVisibility();
/** @var \Magento\Msrp\Helper\Data $helper */
$helper = $this->helper(Magento\Msrp\Helper\Data::class);
$canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinimalPriceLessMsrp($product);
?>
<tbody class="cart item">
    <tr class="item-info">
        <td data-th="<?= $block->escapeHtml(__('Item')) ?>" class="col item">
            <?php if ($block->hasProductUrl()) :?>
                <a href="<?= $block->escapeUrl($block->getProductUrl()) ?>"
                   title="<?= $block->escapeHtml($block->getProductName()) ?>"
                   tabindex="-1"
                   class="product-item-photo">
            <?php else :?>
                <span class="product-item-photo">
            <?php endif;?>
            <?= $block->getImage($block->getProductForThumbnail(), 'cart_page_product_thumbnail')->toHtml() ?>
            <?php if ($block->hasProductUrl()) :?>
                </a>
            <?php else :?>
                </span>
            <?php endif; ?>
            <div class="product-item-details">
                <strong class="product-item-name">
                    <?php if ($block->hasProductUrl()) :?>
                        <a href="<?= $block->escapeUrl($block->getProductUrl()) ?>"><?= $block->escapeHtml($block->getProductName()) ?></a>
                    <?php else :?>
                        <?= $block->escapeHtml($block->getProductName()) ?>
                    <?php endif; ?>
                </strong>
                <?php if ($_options = $block->getOptionList()) :?>
                    <dl class="item-options">
                        <?php foreach ($_options as $_option) :?>
                            <?php $_formatedOptionValue = $block->getFormatedOptionValue($_option) ?>
                            <dt><?= $block->escapeHtml($_option['label']) ?></dt>
                            <dd>
                                <?php if (isset($_formatedOptionValue['full_view'])) :?>
                                        <?= $block->escapeHtml($_formatedOptionValue['full_view']) ?>
                                    <?php else :?>
                                    <?= $block->escapeHtml($_formatedOptionValue['value'], ['span', 'a']) ?>
                                <?php endif; ?>
                            </dd>
                        <?php endforeach; ?>
                    </dl>
                <?php endif;?>
                <?php if ($messages = $block->getMessages()) :?>
                    <?php foreach ($messages as $message) :?>
                        <div class= "cart item message <?= $block->escapeHtmlAttr($message['type']) ?>">
                            <div><?= $block->escapeHtml($message['text']) ?></div>
                        </div>
                    <?php endforeach; ?>
                <?php endif; ?>
                <?php $addInfoBlock = $block->getProductAdditionalInformationBlock(); ?>
                <?php if ($addInfoBlock) :?>
                    <?= $addInfoBlock->setItem($_item)->toHtml() ?>
                <?php endif;?>
            </div>
        </td>

        <?php if ($canApplyMsrp) :?>
            <td class="col msrp" data-th="<?= $block->escapeHtml(__('Price')) ?>">
                <span class="pricing msrp">
                    <span class="msrp notice"><?= $block->escapeHtml(__('See price before order confirmation.')) ?></span>
                    <?php $helpLinkId = 'cart-msrp-help-' . $_item->getId(); ?>
                    <a href="#" class="action help map"
                       id="<?= ($block->escapeHtmlAttr($helpLinkId)) ?>"
                       data-mage-init='{"addToCart":{
                                            "helpLinkId": "#<?= $block->escapeJs($block->escapeHtml($helpLinkId)) ?>",
                                            "productName": "<?= $block->escapeJs($block->escapeHtml($product->getName())) ?>",
                                            "showAddToCart": false
                                            }
                                        }'
                    >
                        <span><?= $block->escapeHtml(__("What's this?")) ?></span>
                    </a>
                </span>
            </td>
        <?php else :?>
            <td class="col price" data-th="<?= $block->escapeHtml(__('Price')) ?>">
                <?= $block->getUnitPriceHtml($_item) ?>
            </td>
        <?php endif; ?>
        <td class="col qty" data-th="<?= $block->escapeHtml(__('Qty')) ?>">
            <div class="field qty">
                <div class="control qty custom-qty clearfix">
                    <label for="cart-<?= $block->escapeHtmlAttr($_item->getId()) ?>-qty">
                        <span class="label"><?= $block->escapeHtml(__('Qty')) ?></span>
                        <a class="alo_qty alo_qty_dec ajax-cart-qty-minus" href="javascript:void(0)"></a>
                        <input id="cart-<?= $block->escapeHtmlAttr($_item->getId()) ?>-qty"
                               name="cart[<?= $block->escapeHtmlAttr($_item->getId()) ?>][qty]"
                               data-cart-item-id="<?= $block->escapeHtmlAttr($_item->getSku()) ?>"
                               value="<?= $block->escapeHtmlAttr($block->getQty()) ?>"
                               type="number"
                               size="4"
                               step="any"
                               title="<?= $block->escapeHtmlAttr(__('Qty')) ?>"
                               class="input-text qty"
                               data-validate="{required:true,'validate-greater-than-zero':true}"
                               data-role="cart-item-qty"/>
                        <a class="alo_qty alo_qty_inc ajax-cart-qty-plus" href="javascript:void(0)"></a>
                    </label>
                </div>
            </div>
        </td>

        <td class="col subtotal" data-th="<?= $block->escapeHtml(__('Subtotal')) ?>">
            <?php if ($canApplyMsrp) :?>
                <span class="cart msrp subtotal">--</span>
            <?php else :?>
                <?= $block->getRowTotalHtml($_item) ?>
            <?php endif; ?>
        </td>
    </tr>
    <tr class="item-actions">
        <td colspan="4">
            <div class="actions-toolbar">
                <?= /* @noEscape */ $block->getActions($_item) ?>
            </div>
        </td>
    </tr>
</tbody>
<script type="text/javascript">
    require(['jquery', 'AjaxCart'], function ($) {
    });
</script>

As per highlighted code in above files, we will add our JS files.
First we will add our JS configuration in app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/requirejs-config.js file.

var config = {
    map: {
        '*': {
            'AjaxCart': 'Magelearn_AjaxShoppingCartUpdate/js/cartValueIncDec',
            'CartQtyUpdate': 'Magelearn_AjaxShoppingCartUpdate/js/cartQtyUpdate'
        }
    },
    shim: {
        AjaxCart: {
            deps: ['jquery']
        },
        CartQtyUpdate: {
            deps: ['jquery']
        }
    }
};

Now as per filepath defined in above file add app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/web/js/cartValueIncDec.js file.

define(['jquery'], function ($) {
    "use strict";
        function ajaxCartUpdate() {
            $('.main').on("click", '.alo_qty_dec', function () {
                var input = $(this).parent().find('input');
                var value = parseInt(input.val());
                if (value) input.val(value - 1);
            });
            $('.main').on("click", '.alo_qty_inc', function () {
                var input = $(this).parent().find('input');
                var value = parseInt(input.val());
                input.val(value + 1);
            });
        }

        ajaxCartUpdate();
});

And app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/web/js/cartQtyUpdate.js file.

define(['jquery'], function ($) {
    "use strict";
    function cartQtyupdate() {
        var form = $('form#form-validate');
        $.ajax({
            url: form.attr('action'),
            data: form.serialize(),
            showLoader: true,
            success: function (res) {
                var parsedResponse = $.parseHTML(res);
                var result = $(parsedResponse).find("#form-validate");
                var sections = ['cart'];

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

                require(['Magento_Checkout/js/action/get-totals',
                    'Magento_Customer/js/customer-data'], function (getTotalsAction, customerData) {
                    // The mini cart reloading
                    customerData.reload(sections, true);

                    // The totals summary block reloading
                    var deferred = $.Deferred();
                    getTotalsAction([], deferred);

                    //Display error if found after jquery
                    var messages = $.cookieStorage.get('mage-messages');
                    if (!_.isEmpty(messages)) {
                        customerData.set('messages', {messages: messages});
                        $.cookieStorage.set('mage-messages', '');
                    }
                });
            },
            error: function (xhr, status, error) {
                var err = eval("(" + xhr.responseText + ")");
                console.log(err.Message);
            }
        });
    }

    $(document).on('change', '.custom-qty input', function () {
        cartQtyupdate();
    });
    $(document).on('click', '.custom-qty a', function () {
        cartQtyupdate();
    });
});

Now to add +/- qty on cart items and AJAX operation on checkout page we will add app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/layout/checkout_index_index.xml file.

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="sidebar" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="summary" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="cart_items" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="details" xsi:type="array">
                                                            <item name="component"
                                                                  xsi:type="string">Magelearn_AjaxShoppingCartUpdate/js/view/summary/item/details</item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Now as per path defined in above layout file, we will add our JS component file at app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/web/js/view/summary/item/details.js

define([
	'jquery',
    'uiComponent',
    'Magento_Customer/js/model/authentication-popup',
    'Magento_Customer/js/customer-data',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/action/get-totals',
    'Magento_Checkout/js/model/totals',
    'Magento_Checkout/js/model/cart/totals-processor/default',
    'Magento_Checkout/js/model/cart/cache',
    'Magento_Checkout/js/model/shipping-service',
    'Magento_Checkout/js/model/shipping-rate-registry',
    'Magento_Checkout/js/model/resource-url-manager',
    'mage/storage',
    'Magento_Checkout/js/model/error-processor',
    'mage/url',
    'Magento_Ui/js/modal/alert',
    'Magento_Ui/js/modal/confirm',
    'underscore',
    'escaper',
    'jquery/ui',
    'mage/decorate',
    'mage/collapsible',
    'mage/cookies'
], function ($,
Component,
authenticationPopup,
customerData,
quote,
getTotalsAction,
totals,
defaultTotal,
cartCache,
shippingService,
rateRegistry,
resourceUrlManager,
storage,
errorProcessor,
url,
alert,
confirm,
_,
escaper) {
    'use strict';

    return Component.extend({
		shoppingCartUrl: window.checkout.shoppingCartUrl,
        defaults: {
            template: 'Magelearn_AjaxShoppingCartUpdate/summary/item/details',
            allowedTags: ['b', 'strong', 'i', 'em', 'u']
        },

        /**
         * @param {Object} quoteItem
         * @return {String}
         */
        getNameUnsanitizedHtml: function (quoteItem) {
            var txt = document.createElement('textarea');

            txt.innerHTML = quoteItem.name;

            return escaper.escapeHtml(txt.value, this.allowedTags);
        },

        /**
         * @param {Object} quoteItem
         * @return {String}Magento_Checkout/js/region-updater
         */
        getValue: function (quoteItem) {
            return quoteItem.name;
        },
        updateItemQtyCheckout: function (data, event)
        {
            var btnminus = "";
            var btnplus = "";
            if (event.target.classList[1] == "minus")
            {
                btnminus = event.currentTarget.dataset.btnMinus;
            }
            if (event.target.classList[1] == "plus")
            {
                btnplus = event.currentTarget.dataset.btnPlus;
            }
            var itemId = event.currentTarget.dataset.cartItem;


            // If element is minus and quantity is '1' than remove
            var elem = $('#cart-item-' + itemId + '-qty');
            if(event.target.classList[1] == 'plus')
            {
                 elem.val(parseInt(elem.val()) + 1)
            }
            else if(event.target.classList[1] == 'minus')
            {
                elem.val(parseInt(elem.val()) - 1)
            }
                

            if (event.target.classList[1] == "minus" && $('#cart-item-' + itemId + '-qty').val() == '0')
            {
                var productData = this._getProductById(Number(itemId));

                if (!_.isUndefined(productData))
                {
                    var self = this;
                    var elemr = elem;
                    self._ajax(url.build('checkout/sidebar/removeItem'), {
                                    'item_id': itemId
                                }, elemr, self._removeItemAfter);

                    if (window.location.href === self.shoppingCartUrl)
                    {
                          window.location.reload(false);
                    }
                    
                }
            }
            else
            {
                this._ajax(url.build('checkout/sidebar/updateItemQty'), {
                    'item_id': itemId,
                    'item_qty': $('#cart-item-' + itemId + '-qty').val(),
                    'item_btn_plus': btnplus,
                    'item_btn_minus': btnminus
                }, elem, this._updateItemQtyAfter);
            }
        },
        _getProductById: function (productId)
        {
            return _.find(customerData.get('cart')().items, function (item)
            {
                return productId === Number(item['item_id']);
            });
        },
        _updateItemQtyAfter: function (elem)
        {
            var productData = this._getProductById(Number(elem.data('cart-item')));

            if (!_.isUndefined(productData)) 
            {
                $(document).trigger('ajax:updateCartItemQty');

                if (window.location.href === this.shoppingCartUrl)
                {
                    window.location.reload(false);
                }
            }
            this._hideItemButton(elem);
            this._customerData();
        },
        _customerData: function ()
        {
            var deferred = $.Deferred();
            getTotalsAction([], deferred);
            var sections = ['cart'];
            customerData.invalidate(sections);
            customerData.reload(sections, true);
            
            var totals_obj = totals.totals;
            totals_obj.subscribe(function(newTotalvalue) {
			    //console.dir(newTotalvalue['items'].length);
			    if(window.checkoutConfig.useQty == true) {
					$('.items-in-cart strong span:first').html(newTotalvalue['items_qty']);
				}
			});
			
            var self = this;
            self._estimateTotalsAndUpdateRatesCheckout();
        },
        _ajax: function (url, data, elem, callback)
        {
            $.extend(data, {
                'form_key': $.mage.cookies.get('form_key')
            });

            $.ajax({
                url: url,
                data: data,
                type: 'post',
                dataType: 'json',
                context: this,

                /** @inheritdoc */
                beforeSend: function ()
                {
                    elem.attr('disabled', 'disabled');
                },

                /** @inheritdoc */
                complete: function ()
                {
                    elem.attr('disabled', null);
                }
            })
                .done(function (response)
                {
                    var msg;

                    if (response.success)
                    {
                        callback.call(this, elem, response);
                    }
                    else
                    {
                        msg = response['error_message'];

                        if (msg)
                        {
                            alert({
                                content: msg
                            });
                        }
                    }
                })
                .fail(function (error)
                {
                    console.log(JSON.stringify(error));
                });
        },
        _hideItemButton: function (elem)
        {
            var itemId = elem.data('cart-item');

            $('#update-cart-item-' + itemId).hide('fade', 300);
        },
        _removeItemAfter: function (elem)
        {
            var productData = this._getProductById(Number(elem.data('cart-item')));

            if (!_.isUndefined(productData))
            {
                $(document).trigger('ajax:removeFromCart', {
                    productIds: [productData['product_id']]
                });
                var sections = ['cart'];

                setTimeout(function ()
                {
                    if (customerData.get('cart')().items.length == 0)
                    {
                        window.location.reload();
                    }
                }, 2000);

                if (window.location.href.indexOf(this.shoppingCartUrl) === 0)
                {
                    window.location.reload();
                }
            }
            this._customerData();
        },
        _estimateTotalsAndUpdateRatesCheckout: function ()
        {
            var serviceUrl, payload;
            var address = quote.shippingAddress();
            shippingService.isLoading(true);
            serviceUrl = resourceUrlManager.getUrlForEstimationShippingMethodsForNewAddress(quote);
            payload = JSON.stringify({
                    address: {
                        'street': address.street,
                        'city': address.city,
                        'region_id': address.regionId,
                        'region': address.region,
                        'country_id': address.countryId,
                        'postcode': address.postcode,
                        'email': address.email,
                        'customer_id': address.customerId,
                        'firstname': address.firstname,
                        'lastname': address.lastname,
                        'middlename': address.middlename,
                        'prefix': address.prefix,
                        'suffix': address.suffix,
                        'vat_id': address.vatId,
                        'company': address.company,
                        'telephone': address.telephone,
                        'fax': address.fax,
                        'custom_attributes': address.customAttributes,
                        'save_in_address_book': address.saveInAddressBook
                    }
                }
            );
            storage.post(
                serviceUrl, payload, false
            ).done(function (result) {
                rateRegistry.set(address.getCacheKey(), result);
                shippingService.setShippingRates(result);
            }).fail(function (response) {
                shippingService.setShippingRates([]);
                errorProcessor.process(response);
            }).always(function () {
                shippingService.isLoading(false);
            });
        }
    });
});

Also will add our html file at app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/web/template/summary/item/details.html

<!-- ko foreach: getRegion('before_details') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
<!-- /ko -->
<div class="product-item-details">

    <div class="product-item-inner">
        <div class="product-item-name-block">
            <strong class="product-item-name" data-bind="html: getNameUnsanitizedHtml($parent)"></strong>
            <div class="details-qty">
                <span class="label"><!-- ko i18n: 'Qty' --><!-- /ko --></span>
                <span class="value" data-bind="text: $parent.qty"></span>
                <!-- new code start -->
                <button data-bind="attr: {
                           id: 'minus-cart-item-'+$parent.item_id,
                           'data-cart-item': $parent.item_id,
                           'data-btn-minus': 'minus',
                           },click:updateItemQtyCheckout"
                        class="update-cart-item minus">
                        -
                </button>
                <input data-bind="attr: {
                           id: 'cart-item-'+$parent.item_id+'-qty',
                           'data-cart-item': $parent.item_id,
                           'data-item-qty': $parent.qty,
                           'data-cart-item-id': $parent.product_sku
                           }, value: $parent.qty"
                       type="number"
                       size="4"
                       class="item-qty cart-item-qty" readonly>
 
                <button data-bind="attr: {
                           id: 'plus-cart-item-'+$parent.item_id,
                           'data-cart-item': $parent.item_id,
                           'data-btn-plus': 'plus'
                           },click:updateItemQtyCheckout"
                        class="update-cart-item plus">
                    <!--<span data-bind="i18n: '+'"></span>-->
                    +
                </button>
                <button data-bind="attr: {
                           id: 'update-cart-item-'+$parent.item_id,
                           'data-cart-item': $parent.item_id,
                           title: $t('Update')
                           }"
                        class="update-cart-item"
                        style="display: none">
                    <span data-bind="i18n: 'Update'">
                    </span>
                </button>
                <!--  new code ends -->
            </div>
        </div>
        <!-- ko foreach: getRegion('after_details') -->
            <!-- ko template: getTemplate() --><!-- /ko -->
        <!-- /ko -->
    </div>

    <!-- ko if: (JSON.parse($parent.options).length > 0)-->
    <div class="product options" data-bind="mageInit: {'collapsible':{'openedState': 'active'}}">
        <span data-role="title" class="toggle"><!-- ko i18n: 'View Details' --><!-- /ko --></span>
        <div data-role="content" class="content">
            <strong class="subtitle"><!-- ko i18n: 'Options Details' --><!-- /ko --></strong>
            <dl class="item-options">
                <!--ko foreach: JSON.parse($parent.options)-->
                <dt class="label" data-bind="text: label"></dt>
                    <!-- ko if: ($data.full_view)-->
                    <!-- ko with: {full_viewUnsanitizedHtml: $data.full_view}-->
                    <dd class="values" data-bind="html: full_viewUnsanitizedHtml"></dd>
                    <!-- /ko -->
                    <!-- /ko -->
                    <!-- ko ifnot: ($data.full_view)-->
                    <!-- ko with: {valueUnsanitizedHtml: $data.value}-->
                    <dd class="values" data-bind="html: valueUnsanitizedHtml"></dd>
                    <!-- /ko -->
                    <!-- /ko -->
                <!-- /ko -->
            </dl>
        </div>
    </div>
    <!-- /ko -->
</div>
<!-- ko foreach: getRegion('item_message') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
<!-- /ko -->

We will also add some CSS to display it more properly at app/code/Magelearn/AjaxShoppingCartUpdate/view/frontend/web/css/source/_module.less

0 Comments On "Update Shopping Cart items quantity with AJAX on Checkout/cart and Checkout Page. Display Alert before remove items from cart on Checkout/cart Page"

Back To Top