0

I have created a custom module to add some fields to the order checkout however I have some troubles enabling them conditionally.

I have a radio button and 4 elements

When the radio is clicked, depending on the value, I change the 4 fields to disabled=false or disabled=true and I would like the input fields to either add the attribute disabled or not even display at all

I've added the fields through my layout processor class like this

    class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcessorInterface
    {
        /**
         * @var CustomerSession
         */
        protected $customerSession;

        /**
         * @var HelperData
         */
        protected $helperData;

        /**
         * LayoutProcessor constructor.
         * @param CustomerSession $customerSession
         * @param HelperData $helperData
         */
        public function __construct(
            CustomerSession $customerSession,
            HelperData $helperData
        ) {
            $this->customerSession = $customerSession;
            $this->helperData = $helperData;
        }

        protected function getIsBusinessField()
        {
            $position = $this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION);
            $inputElementTmpl = 'Vendor_Invoicefields/form/element/radio';
            if ($position == 3) {
                $inputElementTmpl = 'Vendor_Invoicefields/form/element/radio_payment';
            }

            $customAttributeCode = 'is_business';
            $customField = [
                'component' => 'Vendor_Invoicefields/js/view/form/element/radio',
                'config' => [
                    'customScope' => 'customCheckoutForm',
                    'template' => 'ui/form/field',
                    'elementTmpl' => $inputElementTmpl
                ],
                'dataScope' => 'customCheckoutForm' . '.' . $customAttributeCode,
                'label' => __('Are you an individual or a business?'),
                'provider' => 'checkoutProvider',
                'sortOrder' => 0,
                'validation' => [
                    'required-entry' => true
                ],
                'options' => [],
                'filterBy' => null,
                'customEntry' => null,
                'visible' => true,
                //'value' => $this->getTaxInformationSession($customAttributeCode)
            ];
            return $customField;
        }

        protected function getLayoutField($customAttributeCode, $label, $required_entry, $sortOrder)
        {
            $position = $this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION);
    //        $inputElementTmpl = 'ui/form/element/input';
            $inputElementTmpl = 'Vendor_Invoicefields/form/element/input';
    //        if ($position == 3) {
    //            $inputElementTmpl = 'Vendor_Invoicefields/form/element/input';
    //        }

            $customField = [
                'component' => 'Magento_Ui/js/form/element/abstract',
                'config' => [
                    'customScope' => 'customCheckoutForm',
                    'template' => 'ui/form/field',
                    'elementTmpl' => $inputElementTmpl
                ],
                'dataScope' => 'customCheckoutForm' . '.' . $customAttributeCode,
                'label' => __($label),
                'provider' => 'checkoutProvider',
                'sortOrder' => $sortOrder,
                'validation' => [
                    'required-entry' => (boolean) $required_entry
                ],
                'additionalClasses' => 'tax_information_group',
                'options' => [],
                'filterBy' => null,
                'customEntry' => null,
                'visible' => true,
                //'value' => $this->getTaxInformationSession($customAttributeCode)
            ];

            return $customField;
        }

        public function getTaxInformationSession($key = '')
        {
            $result = '';
            $tax_information = $this->customerSession->getTaxInformation();
            if (array_key_exists($key, $tax_information) && $tax_information[$key] != "") {
                $result = $tax_information[$key];
            }

            return $result;
        }

        protected function getCompanyNameField()
        {
            $customField = [];
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_COMPANY_NAME)) {
                $required_entry = $this->helperData->getStoreConfig(HelperData::CONFIG_REQUIRE_COMPANY_NAME);
                $customField = $this->getLayoutField('company_name', 'Company Name', $required_entry, 1);
            }
            return $customField;
        }

        protected function getTaxIdField()
        {
            $customField = [];
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_TAX_ID)) {
                $required_entry = $this->helperData->getStoreConfig(HelperData::CONFIG_REQUIRE_TAX_ID);
                $customField = $this->getLayoutField('tax_id', 'Tax ID', $required_entry, 2);
            }
            return $customField;
        }

        protected function getTaxDepartmentField()
        {
            $customField = [];
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_TAX_DEPARTMENT)) {
                $required_entry = $this->helperData->getStoreConfig(HelperData::CONFIG_REQUIRE_TAX_DEPARTMENT);
                $customField = $this->getLayoutField('tax_department', 'Tax Department', $required_entry, 3);
            }
            return $customField;
        }

        protected function getOccupationField()
        {
            $customField = [];
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_OCCUPATION)) {
                $required_entry = $this->helperData->getStoreConfig(HelperData::CONFIG_REQUIRE_OCCUPATION);
                $customField = $this->getLayoutField('occupation', 'Occupation', $required_entry, 4);
            }
            return $customField;
        }

        protected function getCustomCheckoutStep()
        {
            $customAttributeCode = 'tax-information-step';
            $customField = [
                'component' => 'Vendor_Invoicefields/js/view/my-step-view',
                'children' => [
                    'custom-checkout-form-container' => [
                        'component' => 'Vendor_Invoicefields/js/view/custom-checkout-form',
                        'provider' => 'checkoutProvider',
                        'config' => [
                            'template' => 'Vendor_Invoicefields/custom-checkout-form'
                        ],
                        'children' => [
                            'custom-checkout-form-fieldset' => [
                                'component' => 'uiComponent',
                                'displayArea' => 'custom-checkout-form-fields',
                                'children' => []
                            ]
                        ]
                    ]
                ],
                'sortOrder' => 2,
            ];
            return $customField;
        }

        protected function getCustomCheckoutForm()
        {
            $customAttributeCode = 'tax-information-step';
            $customField = [
                'component' => 'Vendor_Invoicefields/js/view/custom-checkout-form',
                'provider' => 'checkoutProvider',
                'config' => [
                    'template' => 'Vendor_Invoicefields/custom-checkout-form-fields'
                ],
                'children' => [
                    'custom-checkout-form-fieldset' => [
                        'component' => 'uiComponent',
                        'displayArea' => 'custom-checkout-form-fields',
                        'children' => []
                    ],
                    'custom-validator' => [
                        'component' => 'Vendor_Invoicefields/js/view/custom-validate'
                    ]

                ]
            ];
            return $customField;
        }

        public function addFieldsToForm(&$parentElement)
        {
            $parentElement['custom-checkout-form-container'] = $this->getCustomCheckoutForm();
            $taxInformationStep = &$parentElement['custom-checkout-form-container']['children']
            ['custom-checkout-form-fieldset']['children'];

            $taxInformationStep['is_business'] = $this->getIsBusinessField();
            $taxInformationStep['company_name'] = $this->getCompanyNameField();
            $taxInformationStep['tax_id'] = $this->getTaxIdField();
            $taxInformationStep['tax_department'] = $this->getTaxDepartmentField();
            $taxInformationStep['occupation'] = $this->getOccupationField();
            return $parentElement;
        }

        /**
         * @param array $jsLayout
         * @return array
         */
        public function process($jsLayout)
        {
            if (!$this->helperData->isModuleEnabled()) {
                return $jsLayout;
            }

            /* Before Shipping Address */
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION) == '1') {
                $beforeShippingAddressPosition = &$jsLayout['components']['checkout']['children']['steps']['children']
                ['shipping-step']['children']['shippingAddress']['children']['before-form']['children'];

                if (isset($beforeShippingAddressPosition)) {
                    $this->addFieldsToForm($beforeShippingAddressPosition);
                }
            }

            /* After Shipping Address */
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION) == '2') {
                if (!$this->customerSession->isLoggedIn()) {
                    $afterShippingAddressPosition = &$jsLayout['components']['checkout']['children']['steps']['children']
                    ['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children'];
                } else {
                    $afterShippingAddressPosition = &$jsLayout['components']['checkout']['children']['steps']['children']
                    ['shipping-step']['children']['shippingAddress']['children']['before-form']['children'];
                }

                if (isset($afterShippingAddressPosition)) {
                    $this->addFieldsToForm($afterShippingAddressPosition);
                }
            }

            /* After Billing Address */
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION) == '3') {
                $afterBillingAddressPosition = &$jsLayout['components']['checkout']['children']['steps']['children']
                ['billing-step']['children']['payment']['children']
                ['payments-list']['children']['before-place-order']['children'];

                if (isset($afterBillingAddressPosition)) {
                    $this->addFieldsToForm($afterBillingAddressPosition);
                }
            }

            /* Before Payment Information */
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION) == '4') {
                $beforePaymentPosition = &$jsLayout['components']['checkout']['children']['steps']['children']
                ['billing-step']['children']['payment']['children']['beforeMethods']['children'];

                if (isset($beforePaymentPosition)) {
                    $this->addFieldsToForm($beforePaymentPosition);
                }
            }

            /* After Payment Information */
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION) == '5') {
                $afterPaymentPosition = &$jsLayout['components']['checkout']['children']['steps']['children']
                ['billing-step']['children']['payment']['children']['afterMethods']['children'];

                if (isset($afterPaymentPosition)) {
                    $this->addFieldsToForm($afterPaymentPosition);
                }
            }

            /* Summary */
            if ($this->helperData->getStoreConfig(HelperData::CONFIG_SHOW_ON_CHECKOUT_POSITION) == '6') {
                $SummaryPosition = &$jsLayout['components']['checkout']['children']['sidebar']['children']
                ['summary']['children'];

                if (isset($SummaryPosition)) {
                    $this->addFieldsToForm($SummaryPosition);
                }
            }

            return $jsLayout;
        }

I then created my radio element

define([
    'Magento_Ui/js/form/element/abstract',
    'jquery',
    'uiRegistry'
], function(Abstract, $, uiRegistry) {
    'use strict';

    return Abstract.extend({
        initialize: function () {
            this._super();
            this.value(0);
            this.hideElement(true);
            return this;
        },
        company_name_field: uiRegistry.get('index = company_name'),
        tax_id_field: uiRegistry.get('index = tax_id'),
        tax_department_field: uiRegistry.get('index = tax_department'),
        occupation_field: uiRegistry.get('index = occupation'),

        /**
         * Handle radio click, return true to check te radio
         */
        click: function(data, event) {
            this.change(event.target.value);
            this.value(event.target.value);
            return true;
        },
        /**
         * Change value of radio
         */
        change: function(value) {
            this.hideElement(value);
        },
        hideElement: function(value) {
            var elements = $('.tax_information_group');
            if (value === '0' || value ===0) {
                elements.hide();
                this.updateElementStatus(true);
            } else if (value === '1' || value === 1) {
                elements.show();
                this.updateElementStatus(false);
            }
        },
        updateElementStatus: function (value) {
            if (this.company_name_field) {
                this.company_name_field.disabled(value);
            }
            if (this.tax_id_field) {
                this.tax_id_field.disabled(value);
            }
            if (this.tax_department_field) {
                this.tax_department_field.disabled(value);
            }
            if (this.occupation_field) {
                this.occupation_field.disabled(value);
            }
        }
    });
});

And finally I added my input element template

<input ko-if="disabled" class="admin__control-text" type="text" data-bind="
        event: {change: userChanges},
        value: value,
        hasFocus: focused,
        valueUpdate: valueUpdate,
        attr: {
            name: inputName,
            placeholder: placeholder,
            'aria-describedby': noticeId,
            id: uid,
            maxlength: 255
    }"/>

As per the devdocs https://devdocs.magento.com/guides/v2.3/ui_comp_guide/concepts/magento-bindings.html

I've tried to use the bindings for disabled but I always receive some type of error.

Case 1

data-bind="
    disable: !isEnabled
"

Uncaught ReferenceError: Unable to process binding "disable: function(){return !isEnabled }"

Case 2

attr: {
                name: inputName,
                placeholder: placeholder,
                'aria-describedby': noticeId,
                id: uid,
                disabled: disabled,
                maxlength: 255
        }

Nothing happens

Case 3

I've tried using the accessors isEnabled, isDisabled in any area either the attribute, or the input element but I get an error that the function is undefined.

I'm not quite sure where I'm doing it wrong. I'm assuming the property disabled is not declared as ko.observable thus it's not reactive in the element but in that case there should be a method responsible for monitoring this. That's why I thought of using the accessor methods but to no avail.

Any help is appreciated because I'm completely new to knockoutjs

1 Answer 1

1

I'm answering my own question. Apparently when switching to production mode and merging / minifying the JS files uiRegistry.get is no longer reliable regarding to timings. Therefore my element was defined in developer mode or without any merging / minifying and undefined in production mode.

I switched the code to use callbacks instead like this and now it safely updates

        uiRegistry.get(['index = company_name', 'index = tax_id', 'index = tax_department', 'index = occupation'], function (company_name, tax_id, tax_department, occupation) {
            if (company_name) {
                company_name.disabled(value);
            }
            if (tax_id) {
                tax_id.disabled(value);
            }

            if (tax_department) {
                tax_department.disabled(value);
            }

            if (occupation) {
                occupation.disabled(value);
            }
        });

For more info: https://alanstorm.com/using-the-uiregistry-asynchronously-and-safely/

Your Answer

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

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