How to Change Shipping Price on Address Field Change in Magento 2 Custom Shipping Method

Customer convenience is the essential aspect of any successful online store. Offering a convenient method of purchasing as well as shipping is part and parcel of improving the customer experience in an online store.

By default, there are 7 different shipping methods in Magento 2. However, if these default methods are not enough for your business, you can create shipping method in Magento 2.

For custom shipping methods, you need to also look out for other behaviour that needs to be smoothly functioning with customization in the same way as with the default feature. This includes accommodating features such as multiple shipping addresses, which may be essential for some customers. Multiple shipping addresses allow customers to easily manage and choose between different shipping destinations for their orders.

For example, the change in shipping price on the address field change when a custom shipping method is selected. Also enhance the user experience by providing real time cost calculation, transparency and essential shipping information by updating checkout summary on selecting shipping method in Magento 2.

The customer has to refresh the page after changing the value of the address field in order to see the updated shipping rate in default Magento 2.

It’s annoying when you have to reload the page to see the effect on shipping rate after changing country, state, and postcode on the checkout page, isn’t it? That’s why I’ve come up with the solution to change shipping price on address field change in Magento 2 custom shipping method.

The below solution saves your customer from reloading the page and offers a customer convenience checkout using ajax.

Method to Change Shipping Price on Address Field Change in Magento 2 Custom Shipping Method

1. Use the below code in checkout_cart_index.xml at Vendor/Module/view/frontend/layout.

<?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.shipping">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="summary-block-config" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="shipping-rates-validation" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="<carrier-name>-rates-validation" xsi:type="array">
                                            <item name="component" xsi:type="string">
                                                Vendor_Module/js/view/shipping-rates-validation/
                                                <carrier-name>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

2. Add the below code in checkout_index_index.xml at Vendor/Module/view/frontend/layout.

<?xml version="1.0"?>
<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="steps" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="shipping-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="step-config" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="shipping-rates-validation" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="<carrier-name>-rates-validation"
                                                                      xsi:type="array">
                                                                    <item name="component" xsi:type="string">
                                                                        Vendor_Module/js/view/shipping-rates-validation/
                                                                        <carrier-name>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

3. Create the file <carrier-name>.js at Vendor/Module/view/frontend/web/js/model/shipping-rates-validation-rules.

define([], function () {
    'use strict';

    return {
        /**
         * @return {Object}
         */
        getRules: function () {
            return {
                'postcode': {
                    'required': true
                },
                'country_id': {
                    'required': true
                },
                'region_id': {
                    'required': true
                },
                'region_id_input': {
                    'required': true
                }
            };
        }
    };
});

Here postcode, country_id, region_id and region_id_input are the checkout field name. Thus you can use other fields also on which you need required:true.

4. Create another <carrier-name>.js at Vendor/Module/view/frontend/web/js/model/shipping-rates-validator and use the below code.

define([
    'jquery',
    'mageUtils',
    '../shipping-rates-validation-rules/<carrier-name>',
    'mage/translate'
], function ($, utils, validationRules, $t) {
    'use strict';

    return {
        validationErrors: [],

        /**
         * @param {Object} address
         * @return {Boolean}
         */
        validate: function (address) {
            var self = this;

            this.validationErrors = [];
            $.each(validationRules.getRules(), function (field, rule) {
                var message, regionFields;

                if (rule.required && utils.isEmpty(address[field])) {
                    message = $t('Field ') + field + $t(' is required.');
                    regionFields = ['region', 'region_id', 'region_id_input'];

                    if (
                        $.inArray(field, regionFields) === -1 ||
                        utils.isEmpty(address.region) && utils.isEmpty(address['region_id'])
                    ) {
                        self.validationErrors.push(message);
                    }
                }
            });

            return !this.validationErrors.length;
        }
    };
});

5. Use the below code in <carrier-name>.js at Vendor/Module/view/frontend/web/js/view/shipping-rates-validation.

define([
    'uiComponent',
    'Magento_Checkout/js/model/shipping-rates-validator',
    'Magento_Checkout/js/model/shipping-rates-validation-rules',
    '../../model/shipping-rates-validator/<carrier-name>',
    '../../model/shipping-rates-validation-rules/<carrier-name>'
], function (Component,
             defaultShippingRatesValidator,
             defaultShippingRatesValidationRules,
             customShippingRatesValidator,
             customShippingRatesValidationRules) {
    'use strict';

    defaultShippingRatesValidator.registerValidator('<carrier-name>', customShippingRatesValidator);
    defaultShippingRatesValidationRules.registerRules('<carrier-name>', customShippingRatesValidationRules);

    return Component;
});

Note : Replace <carrier-name> with your carrier name which you can find in class specified in <mode> tag of app/code/Vendor/Module/etc/config.xml file in which carrier name is specified as protected $_code = ‘<carrier-name>’;

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <carriers>
            <carrier-name>
                <model>Vendor\Module\Model\Carrier\ClassName</model>
            </carrier-name>
        </carriers>
    </default>
</config>

That’s it. Just being informative you can also get selected shipping rate in Magento 2 to know which shipping rate is chosen by customers at checkout page for customizable and information purpose.

Feel free to share the solution with Magento Community via social media.

Thank You.

Sanjay Jethva

Article by

Sanjay Jethva

Sanjay is the co-founder and CTO of Meetanshi with hands-on expertise with Magento since 2011. He specializes in complex development, integrations, extensions, and customizations. Sanjay is one the top 50 contributor to the Magento community and is recognized by Adobe. His passion for Magento 2 and Shopify solutions has made him a trusted source for...