Magento – Magento 2.2.5: How to validate shipping address

checkoutmagento2shipping-addressvalidation

I'm doing Custom Checkout, and here is what i've done til now.
enter image description here

The adea is to use validate so when i click on "Next" button, it gonna check if the checkbox in "Terms of Use", if its checked, then it free to go, but if its not, a validate message will appear.

Here is my code, i've push to github so you guys can easily to watch and re-procedure:
https://github.com/saxsax1995/MagentoCheckoutCustom

So i've follow devdoc and mageplaza
https://devdocs.magento.com/guides/v2.2/howdoi/checkout/checkout_carrier.html
https://www.mageplaza.com/custom-shipping-carrier-validator-magento-2.html

But it still doesn't work.

I've try to console.log() in C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\web\js\view\custom-validation.js but it doesn't run to it.
Do i missing something here? I think i've do everything the devdoc and mageplaza said.

So here is my code:

C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\layout\checkout_index_index.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="checkout"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="Aht_MagentoCheckoutCustom/css/style.css"/>
        <!--<script src="Aht_MagentoCheckoutCustom::js/custom-validator.js"></script>-->
    </head>
    <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="custom-validator" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Aht_MagentoCheckoutCustom/js/view/custom-validation</item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                                <item name="shippingAddress" xsi:type="array">
                                                    <!--<item name="config" xsi:type="array">-->
                                                        <!--<item name="template" xsi:type="string">Aht_MagentoCheckoutCustom/custom-shipping</item>-->
                                                    <!--</item>-->
                                                    <item name="children" xsi:type="array">
                                                        <item name="shipping-address-fieldset" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="delivery-group" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Aht_MagentoCheckoutCustom/js/view/custom-shipping</item>
                                                                    <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                    <item name="sortOrder" xsi:type="string">150</item>
                                                                    <item name="children" xsi:type="array">
                                                                        <item name="delivery-fieldset" xsi:type="array">
                                                                            <!-- uiComponent is used as a wrapper for form fields (its template will render all children as a list) -->
                                                                            <item name="component" xsi:type="string">uiComponent</item>
                                                                            <item name="displayArea" xsi:type="string">delivery-fieldsets</item>
                                                                            <item name="children" xsi:type="array">
                                                                                <item name="delivery_instruction" xsi:type="array">
                                                                                    <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item>
                                                                                    <item name="config" xsi:type="array">
                                                                                        <!--customScope is used to group elements within a single form (e.g. they can be validated separately)-->
                                                                                        <item name="customScope" xsi:type="string">deliveryForm</item>
                                                                                        <item name="template" xsi:type="string">ui/form/field</item>
                                                                                        <item name="elementTmpl" xsi:type="string">ui/form/element/input</item>
                                                                                    </item>
                                                                                    <!-- value element allows to specify default value of the form field -->
                                                                                    <!--<item name="value" xsi:type="string">Yout value here</item>-->
                                                                                    <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                                    <item name="dataScope" xsi:type="string">deliveryForm.delivery_instruction</item>
                                                                                    <item name="label" xsi:type="string">Delivery Instruction:</item>
                                                                                    <item name="sortOrder" xsi:type="string">1</item>
                                                                                </item>
                                                                                <item name="delivery_type" xsi:type="array">
                                                                                    <item name="component" xsi:type="string">Magento_Ui/js/form/element/select</item>
                                                                                    <item name="config" xsi:type="array">
                                                                                        <!--customScope is used to group elements within a single form (e.g. they can be validated separately)-->
                                                                                        <item name="customScope" xsi:type="string">deliveryForm</item>
                                                                                        <item name="template" xsi:type="string">ui/form/field</item>
                                                                                        <item name="elementTmpl" xsi:type="string">ui/form/element/select</item>
                                                                                    </item>
                                                                                    <item name="options" xsi:type="array">
                                                                                        <item name="0" xsi:type="array">
                                                                                            <item name="label" xsi:type="string">Delivery Type 1</item>
                                                                                            <item name="value" xsi:type="string">delivery_type_1</item>
                                                                                        </item>
                                                                                        <item name="1" xsi:type="array">
                                                                                            <item name="label" xsi:type="string">Delivery Type 2</item>
                                                                                            <item name="value" xsi:type="string">delivery_type_2</item>
                                                                                        </item>
                                                                                        <item name="2" xsi:type="array">
                                                                                            <item name="label" xsi:type="string">Delivery Type 3</item>
                                                                                            <item name="value" xsi:type="string">delivery_type_3</item>
                                                                                        </item>
                                                                                    </item>
                                                                                    <!-- value element allows to specify default value of the form field -->
                                                                                    <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                                    <item name="dataScope" xsi:type="string">deliveryForm.delivery_type</item>
                                                                                    <item name="label" xsi:type="string">Delivery Type:</item>
                                                                                    <item name="sortOrder" xsi:type="string">2</item>
                                                                                </item>
                                                                                <item name="term_of_use" xsi:type="array">
                                                                                    <item name="component" xsi:type="string">Magento_Ui/js/form/element/boolean</item>
                                                                                    <item name="config" xsi:type="array">
                                                                                        <!--customScope is used to group elements within a single form (e.g. they can be validated separately)-->
                                                                                        <item name="customScope" xsi:type="string">deliveryForm</item>
                                                                                        <item name="template" xsi:type="string">ui/form/field</item>
                                                                                        <item name="elementTmpl" xsi:type="string">ui/form/element/checkbox</item>
                                                                                    </item>
                                                                                    <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                                    <item name="dataScope" xsi:type="string">deliveryForm.term_of_use</item>
                                                                                    <item name="description" xsi:type="string">I accept the Terms of Use and Privacy Policy
                                                                                        Sorry, you must accept our Terms of Use and our Privacy Policy before placing your order</item>
                                                                                    <item name="sortOrder" xsi:type="string">3</item>
                                                                                </item>
                                                                            </item>
                                                                        </item>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\web\js\model\custom-shipping-rates-validation-rules.js

define(
    [],
    function () {
        'use strict';
        return {
            getRules: function() {
                return {
                    'term_of_use': {
                        'required': true
                    }
                };
            }
        };
    }
)

C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\web\js\model\custom-validator.js

define(
    [
        'jquery',
        'mageUtils',

        './custom-shipping-rates-validation-rules',
        'mage/translate'
    ],
    function ($, utils, validationRules, $t) {
        'use strict';
        return {
            validationErrors: [],
            validate: function (address) {
                var self = this;
                this.validationErrors = [];
                $.each(validationRules.getRules(), function (field, rule) {
                    if (rule.required && utils.isEmpty(address[field])) {
                        var message = $t('Field ') + field + $t(' is required.');
                        self.validationErrors.push(message);
                    }
                });
                return !Boolean(this.validationErrors.length);
            }
        };
    });

C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\web\js\view\custom-validation.js

define(
    [
        'uiComponent',
        'Magento_Checkout/js/model/shipping-rates-validator',
        'Magento_Checkout/js/model/shipping-rates-validation-rules',
        'Aht_MagentoCheckoutCustom/js/model/custom-validator',
        'Aht_MagentoCheckoutCustom/js/model/custom-shipping-rates-validation-rules'
    ],
    function (Component,
              defaultShippingRatesValidator,
              defaultShippingRatesValidationRules,
              shippingRatesValidator,
              shippingRatesValidationRules)
    {
        'use strict';
        console.log('123');
        defaultShippingRatesValidator.registerValidator('custom-validator', shippingRatesValidator);
        defaultShippingRatesValidationRules.registerRules('custom-shipping-rates-validation-rules', shippingRatesValidationRules);
        return Component;
    }
);

In the source, it doesn't even called in my module.
Here is description image:
enter image description here

Please give advice, thanks for reading 🙂

EDIT 1:

After few days looking for solution, look like custom validate for shipping address doesn't work this way.
I've found another solution, follow the submit form event when we click "Next" in setShippingInformation -> validateShippingInformation function in shipping.js
enter image description here

C:\xampp\htdocs\magento\pub\static\frontend\Magento\luma\en_US\Magento_Checkout\js\view\shipping.js

What i'm trying to do is validate the "term of use", and then show validate message after it. Right now, it console.log correctly when i click on "Next" button, but doesn't show correct message. Its always show "false" just like my description image.

So here is what i've done. (i've updated on github if you guys want to see the module)

C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\web\js\view\shipping.js

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

    return function (Target) {
        return Target.extend({
            errorDeliveryValidationMessage: ko.observable(false),
            validateShippingInformation: function () {
                this._super();
                if($('[name="term_of_use"]:checked').length > 0) {
                    console.log('1');
                    return true;
                }
                console.log('2');
                this.errorDeliveryValidationMessage('Please agree our term of use.');
                return false;
            }
        });
    }
});

C:\xampp\htdocs\magento\app\code\Aht\MagentoCheckoutCustom\view\frontend\requirejs-config.js

var config = {
    map: {
        '*': {
            'Magento_Checkout/js/model/shipping-save-processor/default': 'Aht_MagentoCheckoutCustom/js/model/shipping-save-processor/default'
        }
    }
    ,
    'config': {
        'mixins': {
            'Magento_Checkout/js/view/shipping': {
                'Aht_MagentoCheckoutCustom/js/view/shipping': true
            }
        }
    }
};

C:\xampp\htdocs\magento\pub\static\frontend\Magento\luma\en_US\Aht_MagentoCheckoutCustom\template\shipping-delivery\delivery-form.html

<form class="form form-shipping-delivery" id="co-shipping-delivery-form" data-bind="attr: {'data-hasrequired': $t('* Required Fields')}">
    <div id="shipping-delivery" class="fieldset delivery">
        <!-- ko foreach: getRegion('delivery-fieldsets') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
    </div>
</form>
<div role="alert" class="message notice">
    <span text="errorDeliveryValidationMessage()" />
</div>

Best Answer

You can try something like this , add this in your layout checkout_index_index.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
 -->
<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="billing-step" xsi:type="array">
                                        <item name="children" xsi:type="array">
                                            <item name="payment" xsi:type="array">
                                                <item name="children" xsi:type="array">
                                                    <item name="payments-list" xsi:type="array">
                                                        <item name="children" xsi:type="array">
                                                            <item name="before-place-order" xsi:type="array">
                                                                <item name="children" xsi:type="array">
                                                                    <item name="agreements" xsi:type="array">
                                                                        <item name="component" xsi:type="string">Aht_MagentoCheckoutCustom/js/view/custom-js</item>
                                                                        <item name="sortOrder" xsi:type="string">100</item>
                                                                        <item name="displayArea" xsi:type="string">before-place-order</item>
                                                                        <item name="dataScope" xsi:type="string">checkoutAgreements</item>
                                                                        <item name="provider" xsi:type="string">checkoutProvider</item>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </item>
            </argument>
        </arguments>
    </referenceBlock>
</body>

in Aht\MagentoCheckoutCustom\view\frontend\web\js\view\custom-js.js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

 define([
'ko',
'jquery',
'uiComponent',
'Magento_CheckoutAgreements/js/model/agreements-modal'
], function (ko, $, Component, agreementsModal) {
//put the logic here
});
Related Topic