Skip to content

Understanding data bind at minicart in magento 2

I am using magento 2

in mini cart, I am trying to get the event during which product is being added and removed, a specific item not by cart

enter image description here

enter image description here

shown is the item that exists in mini cart, I want that when the user click the “Update” button it is able to retrieve the details of that product being updated in javascript

I am able to get the location of the code here at

vendor/magento/module-checkout/view/frontend/web/template/minicart/item/default.html

I am able to know that this is the correct code

<div class="details-qty qty">
        <label class="label" data-bind="i18n: 'Qty', attr: {
                for: 'cart-item-'+item_id+'-qty'}"></label>
        <input data-bind="attr: {
                id: 'cart-item-'+item_id+'-qty',
                'data-cart-item': item_id,
                'data-item-qty': qty,
                'data-cart-item-id': product_sku
                }, value: qty"
                type="number"
                size="4"
                class="item-qty cart-item-qty">
        <button data-bind="attr: {
                id: 'update-cart-item-'+item_id,
                'data-cart-item': item_id,
                title: $t('Update')
                }"
                class="update-cart-item"
                style="display: none">
            <span data-bind="i18n: 'Update'"></span>
        </button>
    </div>
</div>

because when I try to change the ‘Update’ value to a different value it is reflected into the mini cart

Thus from this view I try to find where the javascript is being triggered , I search for any input that trigger the class ‘update-cart-item’ and able to find the location of code that call the tempate file that contains ‘update-cart-item’ is at here

app/design/frontend/MageBig/martfury/project01/Magento_Checkout/web/js/view/summary/item/details.js

content of the code are as below

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] == 'remove'){
                elem.val(0)
            }else if(event.target.classList[1] == 'minus'){
                elem.val(parseInt(elem.val()) - 1)
            }
                

            if ((event.target.classList[1] == "minus" || event.target.classList[1] == "remove") && $('#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);
            });
        }
    });
});

```

this code here render the template from 

```
app/design/frontend/MageBig/martfury/project01/Magento_Checkout/web/template/summary/item/details.html
```

and the code content is as below

```

<!-- 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-price-container">
                <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">+</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>
                <!-- ko foreach: getRegion('after_details') -->
                    <!-- ko template: getTemplate() --><!-- /ko -->
                <!-- /ko -->
            </div>
        </div>
        <div class="actions">
            <button data-bind="attr: {id: 'remove-cart-item-'+$parent.item_id,'data-cart-item': $parent.item_id,'data-btn-remove': 'remove',},click:updateItemQtyCheckout" class="update-cart-item remove">
                <svg xmlns="http://www.w3.org/2000/svg" width="10.828" height="10.828" viewBox="0 0 10.828 10.828">
                    <g id="cross" transform="translate(1.414 1.414)">
                        <path id="Path_5049" data-name="Path 5049" d="M0,0,8,8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"/>
                        <line id="Line_204" data-name="Line 204" y1="8" x2="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
                    </g>
                </svg>
            </button>
        </div>
    </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 -->

this code then render this file below in which you can see that the there is the code

click:updateItemQtyCheckout

which seems to refer to the function during which mini cart item is updated

app/design/frontend/MageBig/martfury/project/Magento_Checkout/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: $parent.name">
            </strong>
            <div class="details-qty-price-container">
                <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">+</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>
                <!-- ko foreach: getRegion('after_details') -->
                    <!-- ko template: getTemplate() --><!-- /ko -->
                <!-- /ko -->
            </div>
        </div>
        <div class="actions">
            <button data-bind="attr: {id: 'remove-cart-item-'+$parent.item_id,'data-cart-item': $parent.item_id,'data-btn-remove': 'remove',},click:updateItemQtyCheckout" class="update-cart-item remove">
                <svg xmlns="http://www.w3.org/2000/svg" width="10.828" height="10.828" viewBox="0 0 10.828 10.828">
                    <g id="cross" transform="translate(1.414 1.414)">
                        <path id="Path_5049" data-name="Path 5049" d="M0,0,8,8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="2"/>
                        <line id="Line_204" data-name="Line 204" y1="8" x2="8" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
                    </g>
                </svg>
            </button>
        </div>
    </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 -->

I try to put alert(“Test”) and console.log(“Test”); to see if able to capture the code when the minicart product is being updated, unfortunately nothing happened,

I do not understand how the code click:updateItemQtyCheckout behave and how do I execute javascript code during this event happen

Any help is kindly appreciated whether in helping me understand knockout js or code fixing