Hello Magento Friends,
Hope all are healthy and safe. Today I am here with a significant solution that will make your Magento store feature-rich. Magento 2: How to Add Quantity Increment & Decrement Functionality at Checkout Summary.
E-commerce store owners are always finding ways for offering convenience and comfort to customer’s shopping journey. If the customers need to navigate more pages to perform any action, it results in a bad user experience of the store. One such case is increasing and decreasing product quantity.
Customers can only increase or decrease the product quantity on the cart or mini cart. But sometimes we need to add this functionality to the checkout summary page. The customers can easily perform increment and decrement of product quantity or even remove the product from the checkout page without moving to the cart page or mini cart.
Let’s find out the steps to Add Quantity Increment & Decrement Functionality at Checkout Summary in Magento 2.
Contents
Steps to Add Quantity Increment & Decrement Functionality at Checkout Summary in Magento 2:
Step 1: First you need to add /modify the details.html file in the following path
app\design\frontend\Themes\Yourtheme\Magento_Checkout\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 85 |
<!-- 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: $parent.name"> </strong> <div class="details-qty qty"> <label class="label" data-bind="i18n: 'Qty', attr: { for: 'cart-item-'+$parent.item_id+'-qty'}" style="display: none;"> </label> <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> </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)--> <dd class="values" data-bind="html: full_view"> </dd> <!-- /ko --> <!-- ko ifnot: ($data.full_view)--> <dd class="values" data-bind="html: value"> </dd> <!-- /ko --> <!-- /ko --> </dl> </div> </div> <!-- /ko --> </div> <!-- ko foreach: getRegion('item_message') --> <!-- ko template: getTemplate() --><!-- /ko --> <!-- /ko --> |
Step 2: Now add/modify the details.js file in the following path
app\design\frontend\Themes\Yourtheme\Magento_Checkout\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 |
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/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', 'jquery/ui', 'mage/decorate', 'mage/collapsible', 'mage/cookies' ], function ($, Component, authenticationPopup, customerData, quote, getTotalsAction, shippingService, rateRegistry, resourceUrlManager, storage, errorProcessor, url,alert, confirm, _) { 'use strict'; return Component.extend({ shoppingCartUrl: window.checkout.shoppingCartUrl, defaults: { template: 'Magento_Checkout/summary/item/details' }, /** * @param {Object} quoteItem * @return {String} */ 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 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); }); } }); }); |
After implementing the above code the quantity increment & decrement functionality will be added to the checkout summary of your Magento 2 store.
Conclusion:
Hopefully, everyone is able to Add Quantity Increment & Decrement Functionality at Checkout Summary in Magento 2. Besides this, you can also Add Discount Component to Checkout Order Summary in Magento 2.
If you have trouble executing the code, feel free to reach me via comment. I will be glad to help you out. Do share the article on your social media and stay updated for more tutorials.
Happy Coding!
Hi, what is the use of _estimateTotalsAndUpdateRatesCheckout function in .js file? doesn’t the core file already have this function to estimate rate?
Hi Dhiren,
This is a very helpful Code snipped. Thank you very much!
Unfortunately counter of “items in cart” (below order summary) will not refresh after changing the quantity.
Do you have an idea?
Best regards,
Daniel
We haven’t face such issues. Try to check the console or Magento Log File so you can get an idea about this one.
Hi, i too faced similar issue, the “items in cart” remains the same even if increment the quantity
You can use the section update concept with this one hopefully that can resolve your issue.