0

I'm working on Magento2.2.3. I am overriding products on the list page. Exactly I'm adding Already added qty for each product next to the add to cart button on the list page. To show this qty, I made a custom phtml file. Let's call it custom.phtml In custom.phtml file, I add qty_change.js to get qty of each product in mini cart.

This is the part of qty_change.js

define([
    'ko',
    'uiComponent',
    'jquery',
    'Magento_Customer/js/customer-data'
    ], function (ko, Component,$,customerData) { 
        'use strict';
        return Component.extend({

        initialize: function () {
            //initialize parent Component
            this._super();
            this.cart = customerData.get('cart');
            var self = this;
            console.log('loaded------------'+ this.productId);
        },
        /**
         * Retrieves product data by Id.
         *
         * @param {Number} productId - product Id
         * @returns {Object|undefined}
         * @private
         */
        _getProductById: function (productId) {
            return _.find(customerData.get('cart')().items, function (item) {
                return productId === Number(item['product_id']);
            });
        },
        getQty: function(){
            if(this._getProductById(this.productId)){
                this.qty = this._getProductById(this.productId)['qty'];    
            }else this.qty = 0;
            return this.qty;
        },

And this is a custom.phtml file. I'm calling this phtml file in foreach loop of product collection on the list page. So it renders for each product.

<?php 
$_product = $block->getProduct(); 
$qtyIncrementBy = $_product->getQtyIncrementBy();
$stockRegistry= $block->getLayout()->createBlock('Vendor\Module\Block\Catalog\Stock');
$defaultQty = $stockRegistry->getProductMinAllowedQty($_product->getId());
?>
        <div class="input-text qty" data-bind="scope: 'qty_change_<?= $_product->getId() ;?>'">
            <input id="qty_<?= /* @escapeNotVerified */ $_product->getId() ?>"
                   name="qty"
                   readonly
                   data-bind="value: getQty()"
                   type="number"
                   readonly
                   size="4"
                   style="width:50px;display:none;"
                   title="<?= $block->escapeHtml(__('Qty')) ?>"
                   class="input-text"
            />
        </div>

<script type="text/x-magento-init">
{
    "*": {
        "Magento_Ui/js/core/app": {
            "components": {
                "qty_change_<?= $_product->getId() ;?>": {
                    "component": "My_Module/js/qty_change",
                    "defaultQty": <?= $defaultQty ?>,
                    "productId": <?= /* @escapeNotVerified */ $_product->getId() ?>,
                    "qtyIncrement":<?= ($_product->getQtyIncrementBy()) ?? 1; ?>
                }
             }
        }
    }
}
</script>

If I use this it works fine. But In the list page, I use load more button to show more products. So for the loaded products, after I click load more button, knockoutjs is not applying. Just did many google search and found this.

https://magento.stackexchange.com/a/258666/83233

So I changed custom.phtml by using data-mage-init. It looks like this.

<?php 
$_product = $block->getProduct(); 
$qtyIncrementBy = $_product->getQtyIncrementBy();
$stockRegistry= $block->getLayout()->createBlock('Vendor\Module\Block\Catalog\Stock');
$defaultQty = $stockRegistry->getProductMinAllowedQty($_product->getId());
?>
        <div class="input-text qty" 
            data-mage-init='{"My_Module/js/qty_change": {
                "productId": <?php /* @escapeNotVerified */ echo $_product->getId() ?>,
                "defaultQty": <?= $defaultQty ?>
            }}'
            >
            <input id="qty_<?= /* @escapeNotVerified */ $_product->getId() ?>"
                   name="qty"
                   readonly
                   data-bind="value: getQty(), visible: visibleMinusQtyButton()"
                   type="number"
                   readonly
                   size="4"
                   style="width:50px;display:none;"
                   title="<?= $block->escapeHtml(__('Qty')) ?>"
                   class="input-text"
            />
        </div>

But when I ran this code, I got an issue.

knockout.js:3012 Uncaught ReferenceError: Unable to process binding "value: function(){return getQty() }"
Message: getQty is not defined
    at value (eval at createBindingsStringEvaluator (knockout.js:2624), <anonymous>:3:58)
    at updateFromModel (knockout.js:4517)
    at evaluateImmediate (knockout.js:1737)
    at Object.ko.computed.ko.dependentObservable (knockout.js:1946)
    at init (knockout.js:4551)
    at knockout.js:2989
    at Object.ignore (knockout.js:1249)
    at knockout.js:2988
    at Object.arrayForEach (knockout.js:151)
    at applyBindingsToNodeInternal (knockout.js:2974)

I think this is because I didn't define scope. Actually, when I check the network tab in chrome inspect, the qty_change.js is not loading. But how can I define scope dynamically? As you can see, I'm overriding each product on the list page. So I pass different productId to the qty_change.js file and show different qty according to the current added into a mini cart.

Any help should really appreciate. I asked some devs, but not getting any answer yet.

Hope to get your advice soon. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.