0

I am going crazy with knockout on Magento 2, I am new to knockout and I cannot understand what I am doing wrong. I know there are some related questions posted there but each one is different from what I need. I checked all questions posted before, all links on google, still cannot understand why is not working.

I am trying to retrieve the shipping data on product page on Magento 2 and append them with foreach inside template.

That is what I have until now:

calculate.js

define([
    'jquery',
    'mage/translate',
    'mage/storage',
    'mageUtils',
    'uiComponent',
    'ko'
], function (
    $,
    $t,
    storage,
    utils,
    Component,
    ko
) {

    return Component.extend({

        defaults: {
            carrier: null
        },
        initialize: function (config) {
            var self = this;
            this._super();
            this.carrier = ko.observable();
            this.carrier_f(this.sku);
            return this;
        },
        carrier_f: function (sku) {
            var address;
            var postcode;
            var myViewModel;
            var carrier_view = {};

            var serviceUrlCreate, serviceUrl, payload;
            /**
             * Save  values .
             */
            serviceUrl = '/rest/V1/working_function/' + sku;
            payload = JSON.stringify({
                    address: {
                        'city': '',
                        'region_id': '569',
                        'country_id': 'US',
                        'postcode': '',
                    }
                }
            );
            storage.post(
                serviceUrl,
                payload
            ).done(function (response) {
                this.carrier = ko.observable();

                var carrier_view = {
                    'carrier': this.response
                };


                ko.cleanNode($('#shipping_results')[0]);
                ko.applyBindings(carrier_view, $('#shipping_results')[0]);

                console.log(response);

            }).fail(function (response) {
                console.log(response);
            });

        },

        checkShipping: function () {

            console.log(this.sku);
            
            this.carrier_f(this.sku);
        }
        
    });
    
});

form.phtml

<div data-bind="scope: 'shipping_estimate'">
    <ul id="shipping_results" data-bind="foreach: carrier">
        <li>
            <span data-bind="text: carrier_title"></span>
        </li>
    </ul>
</div>
    <button data-bind="click: checkShipping" class="btn-estimate">Check</button>

    <script type="text/x-magento-init">
                                       {
                                          "*": {
                                                  "Magento_Ui/js/core/app": {
                                                         "components": {
                                                             "shipping_estimate": {
                                                                  "component": "Vendor_Name/js/calculate",
                                                                  "sku": "<?= $block->getProduct()->getSku(); ?>"
                                                              }
                                                         }
                                                   }
                                             }
                                        }                                  
    </script>

Ajax Response is like that:

enter image description here

So basically I need to get results on page load and also when click the Check Button (I will add some textbox after), but now there are not results inside, just empty response.

I tried everything, but still not found a solution, the only thing seems working is to change the scope to "anything-else", then the foreach is working, but the click event is not called.

If anyone has the patience to explain me what I am doing wrong I would really appreciate it. Thank you

1 Answer 1

0

You are close to a working solution I think. At a first glance I see that your button is not in scope of your scope binding. So the call to checkShipping will not be called.

I think the code becomes a bit hard to read when one has binding in the code like that. I would take a slightly different approach. Here are some example code (I kept your component imports):

app/code/StackExchange/Shipping/view/frontend/web/js/calculate.js

define([
    'jquery',
    'mage/translate',
    'mage/storage',
    'mageUtils',
    'uiComponent',
    'ko'
], function (
    $,
    $t,
    storage,
    utils,
    Component,
    ko
) {
    return Component.extend({
        defaults: {
            carrier: []
        },
        initObservable: function() {
            this._super().observe(['carrier']);

            return this;
        },
        checkShipping: function () {
            carriers = this.getCarriers();
            this.carrier(carriers);
        },
        getCarriers: function() {
            console.log(this.sku);
            return [
                {
                    carrier_title: 'Free Shipping',
                },
                {
                    carrier_title: 'Expensive shipping',
                }
            ];
        },
    });
});

app/code/StackExchange/Shipping/view/frontend/templates/shipping-estimate.phtml

<div data-bind="scope: 'shipping_estimate'">
    <div>
        <ul id="shipping_results" data-bind="foreach: carrier">
            <li>
                <span data-bind="text: carrier_title"></span>
            </li>
        </ul>
    </div>
    <button data-bind="click: checkShipping" class="btn-estimate">Check</button>
</div>
<script type="text/x-magento-init">
    {
        "*": {
            "Magento_Ui/js/core/app": {
                "components": {
                    "shipping_estimate": {
                        "component": "StackExchange_Shipping/js/calculate",
                        "sku": "someSku"
                    }
                }
            }
        }
    }
</script>

This renders a clickable button like this. That displays the carrier_title from the array when the button is clicked:

enter image description here

Feel free to ask if you have any questions. Good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.