Magento2 Checkout Validation – Trigger Only on Change Event

checkoutevent-observermagento2magento2.3shipping

So I have these code to validate a generated field in the shipping address: VAT number

The requireJs: app/code/VendorName/Checkout/view/frontend/requirejs-config.js

var config = {
    config: {
        mixins: {
            'Magento_Ui/js/lib/validation/validator': {
                'VendorName_Checkout/js/validation/validator-mixin': true
            }
        }
    }
};

Validation logic: app/code/VendorName/Checkout/view/frontend/web/js/validation/validator-mixin.js

/** vat validation method */
define([
    'jquery'
], function ($) {
    'use strict';

    return function (validator) {

        validator.addRule(
            'validate-vat-number',
            function (value) {
                //Validation Logic
            },
            $.mage.__("Invalid Vat Number")
        );

        return validator;
    };
});

And adding the rule to the field: app/code/VendorName/Checkout/Plugin/Block/Checkout/LayoutProcessorPlugin.php

<?php
namespace VendorName\Checkout\Plugin\Block\Checkout;

use Magento\Checkout\Block\Checkout\LayoutProcessor;

/**
 * Class LayoutProcessorPlugin
 * @package VendorName\Checkout\Plugin\Block\Checkout
 */
class LayoutProcessorPlugin
{
    /**
     * @param LayoutProcessor $subject
     * @param $result
     * @return mixed
     */
    public function afterProcess(
        LayoutProcessor $subject,
        $result
    ) {
        $vatAdditionalRules = ['validate-vat-number' => true];

        $result['components']['checkout']['children']['steps']['children']['shipping-step']
        ['children']['shippingAddress']['children']['shipping-address-fieldset']['children']
        ['vat_id']['validation'] = $vatAdditionalRules;

        return $result;
    }
}

The code works well, the validation show error text right when I input any character into the field. This is all good and fun until I add AJAX to my validation logic. Due to AJAX and calling API to the third party and shit, the validation is pretty slow and it doesn't go well with the on-key-up style of Magento validation: If you're typing the VAT number instead of copying it, it will freeze at the 2nd character for a few secs, then freeze at 3rd character for a few sec, and so on.

So now I want to disable that on-key-up validation on my VAT number field and only trigger the validation on the event "change". Is there a clean Magento-way to achieve it?

Best Answer

I found the solution and it's pretty simple. You need to look into the input template in Magento UI:

vendor/magento/module-ui/view/frontend/web/templates/form/element/input.html

<input class="input-text" type="text" data-bind="
    value: value,
    valueUpdate: 'keyup',
    hasFocus: focused,
    attr: {
        name: inputName,
        placeholder: placeholder,
        'aria-describedby': getDescriptionId(),
        'aria-required': required,
        'aria-invalid': error() ? true : 'false',
        id: uid,
        disabled: disabled
    }" />

Here goes the valueUpdate: 'keyup' that tell Magento when every fields in checkout changed its value. Change it to valueUpdate: 'change' or whatever js event will do the job.

However, you will want to do it the clean way: no core editing, and make it impact other working fields as little as possible. So here is how to do it:

1. Copy the input.html to your module dir, and change its name too, because you'll use it for your field only, not all the input fields:

app/code/VendorName/Checkout/view/frontend/web/template/form/element/vatid.html

<input class="input-text" type="text" data-bind="
    value: value,
    valueUpdate: 'change',
    hasFocus: focused,
    attr: {
        name: inputName,
        placeholder: placeholder,
        'aria-describedby': getDescriptionId(),
        'aria-required': required,
        'aria-invalid': error() ? true : 'false',
        id: uid,
        disabled: disabled
    }" />

2. Change the template of your field, in my case it's vat_id:

app/code/VendorName/Checkout/Plugin/Block/Checkout/LayoutProcessorPlugin.php

<?php
namespace VendorName\Checkout\Plugin\Block\Checkout;

use Magento\Checkout\Block\Checkout\LayoutProcessor;

/**
 * Class LayoutProcessorPlugin
 * @package VendorName\Checkout\Plugin\Block\Checkout
 */
class LayoutProcessorPlugin
{
    /**
     * @param LayoutProcessor $subject
     * @param $result
     * @return mixed
     */
    public function afterProcess(
        LayoutProcessor $subject,
        $result
    ) {
        $vatAdditionalRules = ['validate-vat-number' => true];
        $vatElementTmpl = 'VendorName_Checkout/form/element/vatid';

        $result['components']['checkout']['children']['steps']['children']['shipping-step']
        ['children']['shippingAddress']['children']['shipping-address-fieldset']['children']
        ['vat_id']['validation'] = $vatAdditionalRules;
        $result['components']['checkout']['children']['steps']['children']['shipping-step']
        ['children']['shippingAddress']['children']['shipping-address-fieldset']['children']
        ['vat_id']['config']['elementTmpl'] = $vatElementTmpl;

        return $result;
    }
}
Related Topic