Back to Top

Create Dependent Attribute Fields on Customer Registration Form

Updated 31 March 2023

Hello Friends!
In this blog, we are going to learn how we can create dependent fields for custom customer attributes on the customer registration form at the frontend.

In Magento 2, sometimes we need to get some additional information from customers.
For example, if we want to know from where customers got this reference of our store, then we can add custom fields on customer registration to get that information.
We can add multiple options so that customers can choose. But, after all the options, if we want to provide an option to add another option from his end. Then, in that case, there will be a need to add the dependent field in the form.

Here, I have created a boolean option to choose whether the customer wants to add his aadhaar number or not. If he will choose “Yes”, then the “Aadhaar Number” field will be displayed and he can fill in his aadhaar number.

To achieve “custom dependent attributes on customer registration form” functionality, please go through the following steps:

1. First of all, create custom customer attributes in the database. So, create MyCustomerAttributes.php file inside the <magento-root-dir>/app/code/Vendor/CustomModule/Setup/Patch/Data/ directory.

<?php
/**
* Copyright © Vendor, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Vendor\CustomModule\Setup\Patch\Data;

use Magento\Customer\Model\Customer;
use Magento\Eav\Model\Config;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchRevertableInterface;
use Psr\Log\LoggerInterface;

/**
* Class MyCustomerAttributes
* @package Vendor\CustomModule\Setup\Patch\Data
*/
class MyCustomerAttributes implements DataPatchInterface, PatchRevertableInterface
{
   /**
    * @var ModuleDataSetupInterface
    */
   private $moduleDataSetup;

   /**
    * @var EavSetupFactory
    */
   private $eavSetupFactory;
  
   /**
    * @var LoggerInterface
    */
   private $logger;

   /**
    * @var Config
    */
   private $eavConfig;

   /**
    * @var \Magento\Customer\Model\ResourceModel\Attribute
    */
   private $attributeResource;

   /**
    * constructor.
    * @param EavSetupFactory $eavSetupFactory
    * @param Config $eavConfig
    * @param LoggerInterface $logger
    * @param \Magento\Customer\Model\ResourceModel\Attribute $attributeResource
    */
   public function __construct(
       EavSetupFactory $eavSetupFactory,
       Config $eavConfig,
       LoggerInterface $logger,
       \Magento\Customer\Model\ResourceModel\Attribute $attributeResource,
       \Magento\Framework\Setup\ModuleDataSetupInterface $moduleDataSetup
   ) {
       $this->eavSetupFactory = $eavSetupFactory;
       $this->eavConfig = $eavConfig;
       $this->logger = $logger;
       $this->attributeResource = $attributeResource;
       $this->moduleDataSetup = $moduleDataSetup;
   }

   /**
    * {@inheritdoc}
    */
   public function apply()
   {
       $this->moduleDataSetup->getConnection()->startSetup();
       $this->addPhoneAttribute();
       $this->moduleDataSetup->getConnection()->endSetup();
   }

   /**
    * @throws \Magento\Framework\Exception\AlreadyExistsException
    * @throws \Magento\Framework\Exception\LocalizedException
    * @throws \Zend_Validate_Exception
    */
   public function addPhoneAttribute()
   {
       $eavSetup = $this->eavSetupFactory->create();

       $eavSetup->addAttribute(
           \Magento\Customer\Model\Customer::ENTITY,
           'wk_custom_aadhaar_number',
           [
               'type' => 'varchar',
               'label' => 'Aadhaar Number',
               'input' => 'text',
               'source' => '',
               'required' => false,
               'visible' => true,
               'user_defined' => 1,
               'sort_order' => 999,
               'position' => 999,
               'system' => false,
               'backend' => ''
           ]
       );

       $attributeSetId = $eavSetup->getDefaultAttributeSetId(Customer::ENTITY);
       $attributeGroupId = $eavSetup->getDefaultAttributeGroupId(Customer::ENTITY);

       $attribute = $this->eavConfig->getAttribute(Customer::ENTITY, 'wk_custom_aadhaar_number');
       $attribute->setData('attribute_set_id', $attributeSetId);
       $attribute->setData('attribute_group_id', $attributeGroupId);

       $attribute->setData('used_in_forms', [
           'customer_account_create',
           'adminhtml_customer',
           'customer_account_edit',
           'customer_attributes_registration'
       ]);

       $this->attributeResource->save($attribute);


       $eavSetup->addAttribute(
           \Magento\Customer\Model\Customer::ENTITY,
            'wk_custom_want_to_add_aadhaar',
            [
                'type' => 'int',
                'label' => 'Do you want add your aadhaar number?',
                'input' => 'boolean',
                'source' => '',
                'required' => false,
                'visible' => true,
                'position' => 333,
                'system' => false,
                'backend' => ''
            ]
        );
       $attribute = $this->eavConfig->getAttribute(Customer::ENTITY, 'wk_custom_want_to_add_aadhaar');
       $attribute->setData('attribute_set_id', $attributeSetId);
       $attribute->setData('attribute_group_id', $attributeGroupId);

       $attribute->setData('used_in_forms', [
           'customer_account_create',
           'adminhtml_customer',
           'customer_account_edit',
           'customer_attributes_registration'
       ]);

       $this->attributeResource->save($attribute);
   }

   /**
    * {@inheritdoc}
    */
   public static function getDependencies()
   {
       return [];
   }

   /**
    *
    */
   public function revert()
   {
   }

   /**
    * {@inheritdoc}
    */
   public function getAliases()
   {
       return [];
   }
}

2. Create Element.php file inside the <magento-root-dir>/app/code/Vendor/CustomModule/Block/Widget/Form/Renderer/ directory.

<?php
/**
 * @author Vendor
 * @copyright Copyright (c) 2021 Vendor
 * @package Vendor_CustomModule
 */


namespace Vendor\CustomModule\Block\Widget\Form\Renderer;

use Magento\Framework\Data\Form\Element\AbstractElement;

/**
 * @SuppressWarnings(PHPMD.DepthOfInheritance)
 */
class Element extends \Magento\Backend\Block\Widget\Form\Renderer\Fieldset\Element
{
    /**
     * Initialize block template
     */
    protected $_template = 'Vendor_CustomModule::widget/form/renderer/fieldset/element.phtml';
    /**
     * @var Validation
     */
    private $validation;

    /**
     * Element constructor.
     * @param \Magento\Backend\Block\Template\Context $context
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        array $data = []
    ) {
        parent::__construct($context, $data);
    }

    /**
     * @param AbstractElement $element
     * @return string
     */
    public function render(AbstractElement $element)
    {
        $html = parent::render($element);
        return $html;
    }
}

3. Create Fieldset.php file inside the <magento-root-dir>/app/code/Vendor/CustomModule/Block/Widget/Form/Renderer/ directory.

Searching for an experienced
Magento 2 Company ?
Find out More
<?php
/**
 * @author Vendor
 * @copyright Copyright (c) 2021 Vendor
 * @package Vendor_CustomModule
 */

namespace Vendor\CustomModule\Block\Widget\Form\Renderer;


class Fieldset extends \Magento\Backend\Block\Widget\Form\Renderer\Fieldset
{
    protected $_template = 'Vendor_CustomModule::widget/form/renderer/fieldset.phtml';

    public function getRelationJson()
    {
        $depends = $this->getElement()->getData('depends');
        if (!$depends) {
            return '';
        }
        foreach ($depends as &$relation) {
            $relation['parent_attribute_element_uid'] = $this->getJsId(
                'form-field',
                $relation['parent_attribute_code']
            );
            $relation['depend_attribute_element_uid'] = $this->getJsId(
                'form-field',
                $relation['depend_attribute_code']
            );
        }
        $this->getElement()->setData('depends', $depends);

        return $this->getElement()->convertToJson(['depends']);
    }
}

4. Create Boolean.php file inside the <magento-root-dir>/app/code/Vendor/CustomModule/Block/Data/Form/Element/ directory.

<?php
/**
 * @author Vendor
 * @copyright Copyright (c) 2021 Vendor
 * @package Vendor_CustomModule
 */

namespace Vendor\CustomModule\Block\Data\Form\Element;

class Boolean extends \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Boolean
{
    /**
     * @return void
     */
    protected function _construct()
    {
        parent::_construct();
        $values = $this->getValues();
        if (!$this->getRequired()) {
            array_unshift($values, ['label' => ' ', 'value' => '']);
        }
        $this->setValues($values);
    }
}

5. Create element.phtml file inside the <magento-root-dir>/app/code/Vendor/CustomModule/view/frontend/templates/widget/form/renderer/fieldset/ directory.

<?php
/**
 * @author Vendor
 * @copyright Copyright (c) 2021 Vendor
 * @package Vendor_CustomModule
 */
?>

<?php
/* @var $block \Magento\Backend\Block\Widget\Form\Renderer\Fieldset\Element */
$element = $block->getElement();
$note = $element->getNote() ? '<div class="note" id="' . $element->getId() . '-note">' . $element->getNote() . '</div>' : '';
$elementBeforeLabel = $element->getExtType() == 'checkbox admin__control-checkbox' || $element->getExtType() == 'radio admin__control-radio';
$addOn = ($element->getBeforeElementHtml() || $element->getAfterElementHtml()) && !$element->getNoWrapAsAddon();
$fieldId = ($element->getHtmlContainerId()) ? ' id="' . $element->getHtmlContainerId() . '"' : '';
$fieldClass = "admin__field field field-{$element->getId()} {$element->getCssClass()}";
$fieldClass .= ($elementBeforeLabel) ? ' choice' : '';
$fieldClass .= ($addOn) ? ' with-addon' : '';
$fieldClass .= ($element->getRequired()) ? ' required _required' : '';
$fieldClass .= ($note) ? ' with-note' : '';
$fieldClass .= (!$element->getLabelHtml()) ? ' no-label' : '';

$fieldAttributes = $fieldId . ' class="' . $fieldClass . '" '
    . $block->getUiId('form-field', $element->getId())
    . ($element->getFieldExtraAttributes() ? ' ' . $element->getFieldExtraAttributes() : '');
?>

<?php if (!$element->getNoDisplay()): ?>
    <?php if ($element->getType() == 'hidden'): ?>
        <?php echo $element->getElementHtml() ?>
    <?php else: ?>
    <div<?php /* @escapeNotVerified */ echo $fieldAttributes ?>>
        <?php if ($elementBeforeLabel): ?>
            <?php echo $element->getElementHtml() ?>
            <?php echo $element->getLabelHtml() ?>
            <?php /* @escapeNotVerified */ echo $note ?>
        <?php else: ?>
            <?php echo $element->getLabelHtml() ?>
            <div class="admin__field-control control">
                <?php /* @escapeNotVerified */ echo($addOn) ? '<div class="admin__field">' . $element->getElementHtml() . '</div>' : $element->getElementHtml(); ?>
                <?php /* @escapeNotVerified */ echo $note ?>
            </div>
        <?php endif; ?>
        <?php if ($element->getScopeLabel()): ?>
            <div class="field-service" value-scope="<?php /* @escapeNotVerified */ echo $element->getScopeLabel()?>">
            </div>
        <?php endif;?>
    </div>
    <?php endif; ?>
<?php endif; ?>

6. Create fieldset.phtml file inside the <magento-root-dir>/app/code/Vendor/CustomModule/view/frontend/templates/widget/form/renderer/ directory.

<?php
/**
 * @author Vendor
 * @copyright Copyright (c) 2021 Vendor
 * @package Vendor_CustomModule
 */
?>
<?php
    /** @var $block \Vendor\CustomModule\Block\Widget\Form\Renderer\Fieldset */
    /** @var $element \Magento\Framework\Data\Form\Element\Fieldset */
    $element = $block->getElement();
    $containerId = $element->getFieldsetContainerId();
    $id = $element->getHtmlId();
    $isCollapsable = $element->getCollapsable();
    $isWrapped = $containerId || $element->getHeaderBar() || $isCollapsable;
    $titleActions = '<div class="actions">' . $element->getHeaderBar() . '</div>';
    $isField = $element->getFieldsetType() == 'field';
    $advancedAfter = $element->getAdvancedPosition() == 'after'; // To place advanced options inside or after fieldset
    $advancedLabel = $element->getAdvancedLabel();
    if (!isset($advancedLabel)) {
        $advancedLabel = __('Additional Settings');
    }

    $cssClass = ($isField) ? 'field ' . $element->getClass() : 'fieldset admin__fieldset ' . $element->getClass();

    if ($isField) {
        $count = $element->getCountBasicChildren();
        $cssClass .= ($element->hasAdvanced()) ? ' complex' : '';
    }
?>

<?php
/**
 * @todo investigate situations, when the following is needed:
 * echo $element->getHeaderBar();
 * echo $element->getSubFieldsetHtml();
 */ ?>

<?php if ($isWrapped): ?>
<div class="fieldset-wrapper <?php echo ($isCollapsable) ? 'admin__collapsible-block-wrapper ' : ''; ?>"
     id="<?php /* @escapeNotVerified */
     echo $containerId ? $containerId : $id . '-wrapper'; ?>"
     data-role="<?php /* @escapeNotVerified */
     echo $id ?>-wrapper">
    <div class="fieldset-wrapper-title admin__fieldset-wrapper-title">
        <strong <?php /* @escapeNotVerified */
        echo ($isCollapsable) ?
            'class="admin__collapsible-title" data-toggle="collapse" data-target="#' . $id . '-content"' :
            'class="title"'; ?>>
            <span><?php /* @escapeNotVerified */
                echo $element->getLegend() ?></span>
        </strong>
        <?php /* @escapeNotVerified */
        echo $titleActions; ?>
    </div>
    <div class="fieldset-wrapper-content admin__fieldset-wrapper-content<?php echo ($isCollapsable) ? ' collapse' : ''; ?>"
         id="<?php /* @escapeNotVerified */
         echo $id ?>-content"
         data-role="<?php /* @escapeNotVerified */
         echo $id ?>-content">
        <?php endif; ?>

        <?php if (!$element->getNoContainer()): ?>
        <fieldset style="display: none;" class="<?php /* @escapeNotVerified */
        echo $cssClass ?>" id="<?php /* @escapeNotVerified */
        echo $id ?>">
            <?php if ($element->getLegend() && !$isWrapped): ?>
                <div class="<?php /* @escapeNotVerified */
                echo $isField ? 'label admin__field-label' : 'admin__legend' ?> step-title">
                    <span><?php /* @escapeNotVerified */
                        echo $element->getLegend() ?></span>
                </div>
            <?php endif; ?>
            <?php endif; ?>

            <div class="messages">
                <?php if ($element->getComment() && !$isField): ?>
                    <div class="message message-notice"><?php echo $block->escapeHtml($element->getComment()) ?></div>
                <?php endif; ?>
            </div>

            <?php echo ($isField) ? '<div class="control admin__field-control">' : ''; ?>

            <?php if ($element->hasHtmlContent() && !$isField): ?>
                <?php echo $element->getHtmlContent(); ?>
            <?php else: ?>

            <?php if ($isField && $count > 1): ?>
            <div class="fields-group-<?php /* @escapeNotVerified */
            echo $count ?>">
                <?php endif; ?>

                <?php echo $element->getBasicChildrenHtml(); ?>

                <?php echo ($isField && $count > 1) ? '</div>' : '' ?>

                <?php if ($element->getComment() && $isField): ?>
                    <div class="note"><?php echo $block->escapeHtml($element->getComment()) ?></div>
                <?php endif; ?>

                <?php if ($element->hasAdvanced() && !$isField): ?>
                    <?php echo (!$element->getNoContainer() && $advancedAfter) ? '</fieldset>' : '' ?>
                    <details data-mage-init='{"details": {}}' class="details admin__collapsible-block-wrapper"
                             id="details<?php /* @escapeNotVerified */
                             echo $id ?>">
                        <summary class="details-summary admin__collapsible-title"
                                 id="details-summary<?php /* @escapeNotVerified */
                                 echo $id ?>">
                            <span><?php /* @escapeNotVerified */
                                echo $advancedLabel ?></span>
                        </summary>
                        <div class="details-content admin__fieldset" id="details-content<?php /* @escapeNotVerified */
                        echo $id ?>">
                            <?php echo $element->getAdvancedChildrenHtml(); ?>
                        </div>
                    </details>
                <?php elseif ($element->hasAdvanced() && $isField): ?>
                    <div class="nested" id="nested<?php /* @escapeNotVerified */
                    echo $id ?>">
                        <?php echo $element->getAdvancedChildrenHtml(); ?>
                    </div>
                <?php endif; ?>

                <?php echo ($isField) ? '</div>' : ''; ?>

                <?php endif; ?>


                <?php if (!$element->getNoContainer() && !$advancedAfter): ?>
        </fieldset>
    <?php endif; ?>

        <?php if ($isWrapped): ?>
    </div>
</div>
<?php endif; ?>
<script>
    require([
        'jquery',
        "mage/calendar",
        "Vendor_CustomModule/js/view/relation"
    ], function ($, calendar, relation) {
        var currentBeforeSelector,
            beforeBlockSelectors;

        currentBeforeSelector = "form#form-validate .actions-toolbar";

        beforeBlockSelectors = [
            'form#form-validate > fieldset.create.account > .field.gdpr',
            'form#form-validate > fieldset.create.account > .field.captcha',
            'form#form-validate > fieldset.create.account > .actions-toolbar'
        ];

        $.each(beforeBlockSelectors, function (index, value) {
            if ($(value).length > 0) {
                currentBeforeSelector = value;
                return false;
            }
        });

        if ($(currentBeforeSelector).length) {
            if ($(currentBeforeSelector).before($('#group-fields-customer-attributes').show())) {
                <?php if ($block->getRelationJson()) : ?>
                // execute relations after block is pasted
                relation.init(<?php echo $block->getRelationJson() ?>);
                <?php endif; ?>
            }
        }
    });
</script>

7. Create relation.js file inside the <magento-root-dir>/app/code/Vendor/CustomModule/view/frontend/web/js/view/ directory.

define([
    'jquery'
], function($) {
        'use strict';
        return {
            config : {},
            indexedElements : [],
            /**
             * @param {Object[]} options
             * @returns {jquery}
             */
            init: function (options) {
                this.config = options.depends;
                this.initInputElements();
                return this;
            },
            // init parent element listeners
            initInputElements: function() {
                var different = [];
                $.each(this.config, function(key, parentrelation) {
                    var element = this.getElement(parentrelation.parent_attribute_element_uid);
                    if (element != void(0) && element.length && $.inArray(element.selector, different) == -1) {
                        different.push(element.selector);
                        element.on('change', function (event) {
                            this.observer(event);
                            this.indexedElements = [];
                        }.bind(this));
                        // for custom check
                        element.on('check_relations', this.observer.bind(this));
                        element.find('select').each(function (key, input) {
                            $(input).trigger("check_relations");
                        });
                        this.indexedElements = [];
                    }
                }.bind(this));
            },
            getElement: function (id) {
                return $('[data-ui-id="' + id + '"]');
            },
            observer: function (event) {
                var element = $(event.target);
                var block = $(event.currentTarget);
                if (element && block) {
                    var elementId = block.attr('data-ui-id');
                    this.checkDependencies(element, elementId);
                }
            },
            checkDependencies: function (element, elementId) {
                // Find dependents elements
                var elementDependencies = this.findElementDependencies(elementId);
                // Iterate throw elements and show required elements
                $.each(elementDependencies, function(key, relation) {
                    if (this.getElement(relation.depend_id).length) {
                            // Multiselect and select
                        if (this.canShow(relation)) {
                            this.showBlock(relation.depend_id);
                        } else if (this.indexedElements.indexOf(relation.depend_id) < 0) {
                            this.hideBlock(relation.depend_id);
                        }

                    }
                }.bind(this));
            },
            canShow: function (relationToShow) {
                var parentRelations = this.findElementParentDependencies(relationToShow);
                var result = true;

                // check all parent elements
                $.each(parentRelations, function(key, relation) {
                    var block = this.getElement(relation.parent_id);
                    if (result && block.length) {
                        result = !!(this.checkSelect(block.find('select'), relation));
                    }
                }.bind(this));

                return result;
            },
           
            /*
             * check for select, multiselect
             */
            checkSelect: function (element, relation) {
                if (!element.length) {
                    return false;
                }
                return element.val() != void(0) && element.val().indexOf(relation.value) != -1 && element.is(":visible")
            },

            hideBlock: function (id) {
                var element = this.getElement(id);
                element.hide();
                element.find('select').each(function (key, input) {
                    $(input).trigger("check_relations");
                });
            },
            showBlock: function (id) {
                var element = this.getElement(id);
                element.show();
                this.indexedElements.push(id);
                element.find('select').each(function (key, input) {
                    $(input).trigger("check_relations");
                });
            },
            findElementDependencies: function (elementUId) {
                var elements = [];
                $.each(this.config, function(key, item) {
                    if (item.parent_attribute_element_uid == elementUId) {
                        var el = {
                            'depend_id': item.depend_attribute_element_uid,
                            'value': item.parent_option_id
                        };
                        elements.push(el);
                    }
                });
                return elements;
            },
            findElementParentDependencies: function (elementId) {
                var elements = [];
                $.each(this.config, function(key, item) {
                    if (item.depend_attribute_element_uid == elementId.depend_id
                        && item.parent_option_id == elementId.value
                    ) {
                        var el = {
                            'parent_id': item.parent_attribute_element_uid,
                            'depend_id': item.depend_attribute_element_uid,
                            'value': item.parent_option_id
                        };
                        elements.push(el);
                    }
                });
                return elements;
            }
        }
    }
);

8. Create customer_account_create.xml file inside the <magento-root-dir>/app/code/Vendor/CustomModule/view/frontend/layout/ directory.

<?xml version="1.0"?>
<!--
/**
 * @author Vendor
 * @copyright Copyright (c) 2021 Vendor
 * @package Vendor_CustomModule
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="form.additional.info">
            <block class="Vendor\CustomModule\Block\Customer\Form\CustomerAttributes" name="attributes_customer_register" template="customer_attributes.phtml" cacheable="false"/>
        </referenceContainer>
    </body>
</page>

9. Create customer_attributes.phtml file inside the <magento-root-dir>/app/code/Vendor/CustomModule/view/frontend/templates/ directory.

<?php
/**
 * Webkul Software.
 *
 * @category  Webkul
 * @package   Webkul_CustomModule
 * @author    Webkul
 * @copyright Webkul Software Private Limited (https://webkul.com)
 * @license   https://store.webkul.com/license.html
 */
$customerData = $block->getCustomerData();
$aadharNumber = $customerData["wk_custom_aadhaar_number"] ?? "";
$isAadhar = $customerData["wk_custom_want_to_add_aadhaar"] ?? 0;
?>
<legend class="legend"><span>Additional Information</span></legend>
<div class="field">
    <label for="wk_custom_want_to_add_aadhaar" class="label">
    <span><?= $block->escapeHtml(__('Do you want add your aadhar number?')) ?></span></label>
    <div class="control">
        <select name="wk_custom_want_to_add_aadhaar" id="wk_custom_want_to_add_aadhaar" class="select">
            <option value="1" <?= /* @noEscape*/ ($isAadhar==1)?'selected':'';?> ><?= $block->escapeHtml(__('Yes')) ?></option>
            <option value="0" <?= /*noEscape */ ($isAadhar==0)?'selected':'';?>><?= $block->escapeHtml(__('No')) ?></option>
        </select>
    </div>
</div>
<div class="field">
    <label class="label" for="Aadhaar Number">
        <span><?= /** @noEscape */ __('Aadhaar Number');?></span>
    </label>
    <div class="control">
        <input type="text" name="wk_custom_aadhaar_number" id="wk_custom_aadhaar_number" 
               title="<?= /** @noEscape */ __('Aadhaar Number');?>" class="input-text"
               maxlength="12"
        value="<?= /* @noEscape */ $aadharNumber ?>">
    </div>
</div>

10. Create CustomerAttributes.php file inside the <magento-root-dir>/app/code/Vendor/CustomModule/Block/Customer/Form/ directory.

<?php
namespace Vendor\CustomModule\Block\Customer\Form;

use Magento\Backend\Block\Template\Context;
use Magento\Framework\Registry;
use Magento\Framework\Data\FormFactory;
use Vendor\CustomModule\Block\Widget\Form\Renderer\Element;
use Vendor\CustomModule\Block\Widget\Form\Renderer\Fieldset;
use Magento\Eav\Model\Entity\Attribute;
use Magento\Customer\Model\AttributeMetadataDataProvider;
use Magento\Framework\ObjectManagerInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Catalog\Block\Adminhtml\Form;
use Magento\Customer\Model\Session;
use Magento\Framework\DataObjectFactory;

class CustomerAttributes extends Form
{
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * @var Session
     */
    private $session;

    /**
     * @var DataObjectFactory
     */
    private $dataObjectFactory;

    /**
     * @var Element
     */
    private $elementRenderer;

    /**
     * @var AttributeMetadataDataProvider
     */
    private $attributeMetadataDataProvider;

    /**
     * @var ObjectManagerInterface
     */
    private $objectManager;

    /**
     * @var  array
     */
    private $_customerData;

    /**
     * @var Fieldset
     */
    private $fieldsetRenderer;

    /**
     * Attributes constructor.
     *
     * @param Context $context
     * @param Registry $registry
     * @param Session $session
     * @param FormFactory $formFactory
     * @param Fieldset $fieldsetRenderer
     * @param Element $elementRenderer
     * @param ObjectManagerInterface $objectManager
     * @param DataObjectFactory $dataObjectFactory
     * @param AttributeMetadataDataProvider $attributeMetadataDataProvider
     * @param array $data
     */
    public function __construct(
        Context $context,
        Registry $registry,
        Session $session,
        FormFactory $formFactory,
        Fieldset $fieldsetRenderer,
        Element $elementRenderer,
        ObjectManagerInterface $objectManager,
        DataObjectFactory $dataObjectFactory,
        AttributeMetadataDataProvider $attributeMetadataDataProvider,
        array $data = []
    ) {
        parent::__construct($context, $registry, $formFactory, $data);
        $this->session           = $session;
        $this->fieldsetRenderer  = $fieldsetRenderer;
        $this->elementRenderer   = $elementRenderer;
        $this->objectManager     = $objectManager;
        $this->storeManager      = $context->getStoreManager();
        $this->dataObjectFactory = $dataObjectFactory;
        $this->attributeMetadataDataProvider = $attributeMetadataDataProvider;
    }

    /**
     * Check whether attribute is visible on front
     *
     * @param Attribute $attribute
     *
     * @return bool
     */
    public function isAttributeVisibleOnFront(Attribute $attribute)
    {
        return $attribute->getIsVisible();
    }

    protected function _prepareForm()
    {
        /** @var \Magento\Framework\Data\Form $form */
        $form = $this->_formFactory->create();
        $type = 'customer_attributes_registration';

        $attributes = $this->attributeMetadataDataProvider->loadAttributesCollection(
            'customer',
            $type
        );

        if (!$attributes || !$attributes->getSize()) {
            return;
        }
        $fieldset = $form->addFieldset(
            'group-fields-customer-attributes',
            [
                'class' => 'user-defined',
                'legend' => __('Additional Information')
            ]
        );
        $fieldset->setRenderer($this->fieldsetRenderer);

        $this->_setFieldset($attributes, $fieldset);
        $this->prepareDependentAttributes($attributes, $fieldset);

        $this->setForm($form);
    }

    /**
     * @inheritdoc
     */
    protected function _initFormValues()
    {
        if ($form = $this->getForm()) {
            if ($this->getCustomerData()) {
                $form->addValues($this->getCustomerData());
            }
            /** @var \Magento\Customer\Block\Form\Register $registerForm */
            $registerForm = $this->getLayout()->getBlock('customer_form_register');
            if (is_object($registerForm) && $registerForm->getFormData() instanceof \Magento\Framework\DataObject) {
                $form->addValues($registerForm->getFormData()->getData());
            }
        }

        return parent::_initFormValues();
    }

    /**
     * Set Fieldset to Form
     *
     * @param array|\Magento\Customer\Model\ResourceModel\Form\Attribute\Collection $attributes
     * $attributes - attributes that will be added
     * @param \Magento\Framework\Data\Form\Element\Fieldset $fieldset
     * @param array $exclude
     * @return void
     */
    protected function _setFieldset($attributes, $fieldset, $exclude = [])
    {
        $this->_addElementTypes($fieldset);

        foreach ($attributes as $attribute) {
            /** @var $attribute \Magento\Eav\Model\Entity\Attribute */
            if (!$this->isAttributeVisibleOnFront($attribute)) {
                continue;
            }
            $attribute->setStoreId($this->storeManager->getStore()->getId());

            if ($inputType = $attribute->getFrontend()->getInputType()) {
                $rendererClass = $attribute->getFrontend()->getInputRendererClass();
                
                if ($inputType == "boolean") {
                    $fieldType = 'Webkul\CustomModule\Block\Data\Form\Element\\' . ucfirst($inputType);
                } else {
                    $fieldType = 'Magento\Framework\Data\Form\Element\\' . ucfirst($inputType);
                }
                
                if (!empty($rendererClass)) {
                    $fieldType = $inputType . '_' . $attribute->getAttributeCode();
                    $fieldset->addType($fieldType, $rendererClass);
                }

                $data = [
                    'name' => $attribute->getAttributeCode(),
                    'label' => $attribute->getStoreLabel(),
                    'class' => $attribute->getFrontend()->getClass(),
                    'required' => $attribute->getIsRequired() || $attribute->getRequiredOnFront(),
                    'note' => $attribute->getNote()
                ];
               
                $element = $fieldset->addField(
                    $attribute->getAttributeCode(),
                    $fieldType,
                    $data
                )->setEntityAttribute(
                    $attribute
                );

                $element->setValue($attribute->getDefaultValue());
                $element->setRenderer($this->elementRenderer);
                $element->setAfterElementHtml($this->_getAdditionalElementHtml($element));

                /* add options format */
                $this->_applyTypeSpecificConfig($inputType, $element, $attribute);
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function _applyTypeSpecificConfig($inputType, $element, Attribute $attribute)
    {
        switch ($inputType) {
            case 'select':
                $element->addElementValues($attribute->getSource()->getAllOptions(true, false));
                break;
            case 'multiselect':
                $element->addElementValues($attribute->getSource()->getAllOptions(false, false));
                $element->setCanBeEmpty(true);
                break;
            default:
                break;
        }
    }

    /**
     * @param \Magento\Customer\Model\ResourceModel\Form\Attribute\Collection $attributes
     * @param \Magento\Framework\Data\Form\Element\Fieldset $fieldset
     */
    protected function prepareDependentAttributes($attributes, $fieldset)
    {
        $depends = [];
        $attributeIds = $attributes->getColumnValues('attribute_id');
        if (empty($attributeIds)) {
            return;
        }
       
        //you can add array options dynamically as per your need
        $depends[] = [
            'parent_attribute_id' => 163,
            'parent_attribute_code' => 'wk_custom_want_to_add_aadhaar',
            'parent_option_id' => 1,
            'depend_attribute_id' => 162,
            'depend_attribute_code' => 'wk_custom_aadhaar_number'
        ];
      
        if (!empty($depends)) {
            $fieldset->setData('depends', $depends);
        }
    }

    /**
     * @return array
     */
    private function getCustomerData()
    {
        if (!isset($this->_customerData)) {
            $this->_customerData = [];
            if ($this->session->isLoggedIn()) {
                $this->_customerData = $this->session->getCustomer()->getData();
            }
        }

        return $this->_customerData;
    }
}

11. Now, run the following commands.

php bin/magento setup:upgrade

php bin/magento setup:static-content:deploy

php bin/magento cache:flush

12. Now, check the result(refer to the following images):

customAttributesInDb
patchListinDb
Create-New-Custo
Create-New-Custo-2

Hope this will be helpful. Thanks 🙂

Next Blog: Display dependent fields on the customer account edit page.

Previous Blog: Make Submenu position right adjacent of parent menu at frontend in Magento 2

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


Be the first to comment.

Back to Top

Message Sent!

If you have more details or questions, you can reply to the received confirmation email.

Back to Home