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:

1
2
3
4
5
6
7
8
9
<?php
 
use Magento\Framework\Component\ComponentRegistrar;
 
ComponentRegistrar::register(
    ComponentRegistrar::MODULE,
    'Magelearn_AjaxShoppingCartUpdate',
    __DIR__
);

Add composer.json file in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "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:

1
2
3
4
5
<?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.

1
2
3
4
5
6
7
8
9
10
<?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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0"?>
    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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!-- 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

Related Post:

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