3

Having 2 Drop-downs where the second one should load options according to the first one selections, but both come from the EAV models, I want to make them work in the admin but I can understand how to, I already populated the options from DB, but how to interconnect them is what I can't see

My form.xml file looks like this:

<fieldset name="General">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="label" xsi:type="string"/>
            </item>
        </argument>
        <field name="datafeed_id">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Vendor\Module\Model\Filters\Attribute\Source\Config</item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" translate="true" xsi:type="string">DataFeed</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="source" xsi:type="string">Filters</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                    <item name="dataScope" xsi:type="string">datafeed_id</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">false</item>
                    </item>
                </item>
            </argument>
        </field>
        <field name="attr_code">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Vendor\Module\Model\Filters\Attribute\Source\Attributes</item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" translate="true" xsi:type="string">Attribute</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="source" xsi:type="string">Filters</item>
                    <item name="sortOrder" xsi:type="number">20</item>
                    <item name="dataScope" xsi:type="string">attr_code</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">false</item>
                    </item>
                </item>
            </argument>
        </field>
        <field name="eval_op">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Vendor\Module\Model\Filters\Attribute\Source\Operators</item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" translate="true" xsi:type="string">Operator</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="source" xsi:type="string">Filters</item>
                    <item name="sortOrder" xsi:type="number">30</item>
                    <item name="dataScope" xsi:type="string">eval_op</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">false</item>
                    </item>
                </item>
            </argument>
        </field>
        <field name="eval_val">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Vendor\Module\Model\Filters\Attribute\Source\Conditions</item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" translate="true" xsi:type="string">Condition</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="source" xsi:type="string">Filters</item>
                    <item name="sortOrder" xsi:type="number">40</item>
                    <item name="dataScope" xsi:type="string">eval_val</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">false</item>
                    </item>
                </item>
            </argument>
        </field>
        <field name="filter_status">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Vendor\Module\Model\Filters\Attribute\Source\Status</item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" translate="true" xsi:type="string">Status</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="source" xsi:type="string">Filters</item>
                    <item name="sortOrder" xsi:type="number">50</item>
                    <item name="dataScope" xsi:type="string">filter_status</item>
                    <item name="validation" xsi:type="array">
                        <item name="required-entry" xsi:type="boolean">false</item>
                    </item>
                </item>
            </argument>
        </field>
    </fieldset>
1
  • Yeah I checked it but that is not working for Data retrieved from DB depending on the first drop-down field the data for the second one should load dynamically Commented Sep 25, 2017 at 12:04

2 Answers 2

1

There are several ways how to do this, so below is just one example. For purpose of simplicity lets say that you have one select(A), and based on its value (or change of its value) you want to load new options for the other select (B) (with ajax in this example). The example below was used where select A represented attributes in magento and it was populating select B with their options.

You want to create new component for the select A that looks something like this:

define([
    'jquery',
    'Magento_Ui/js/form/element/select',
    'uiRegistry'
], function ($, Select, uiRegistry) {
    var self;

    return Select.extend({
        initialize: function () {
            self = this;
            this._super();

            self.value.subscribe(function () {
                self.updateValueOptions();
            });

            return this;
        },

        /**
         * Update options in value select.
         */
        updateValueOptions: function () {
            if (self.value()) {
                $.ajax({
                    url: 'http://myajaxcallback.com/',
                    type: 'post',
                    dataType: 'json',
                    cache: false,
                    showLoader: true,
                    data: {attributeId: self.value()}
                }).
                done(function (response) {
                    if (!response.error) {
                        uiRegistry.get('my_form.my_form.fieldsetname.bselectname').
                        options(response.options);
                    }
                });
            }
            else {
                uiRegistry.get('my_form.my_form.fieldsetname.bselectname').options([]);
            }
        }
    });
});

Each time the value of select A changes(attribute in this case), this component will take the value and if it's not empty it will start ajax request to your controller looking for json data.

The controller should look something like this:

    <?php
namespace Company\Values\Controller\Adminhtml\Values;

use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultFactory;

class Load extends \Magento\Backend\App\Action
{

    /** @var \Magento\Eav\Api\AttributeRepositoryInterface */
    private $eavAttributeRepository;

    /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute */
    private $eavAttributeResource;

    /**
     * Load constructor.
     * @param \Magento\Backend\App\Action\Context $context
     * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute $eavAttributeResource
     * @param \Magento\Eav\Api\AttributeRepositoryInterface $eavAttributeRepository
     */
    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Eav\Model\ResourceModel\Entity\Attribute $eavAttributeResource,
        \Magento\Eav\Api\AttributeRepositoryInterface $eavAttributeRepository
    ) {
        parent::__construct($context);
        $this->eavAttributeRepository = $eavAttributeRepository;
        $this->eavAttributeResource   = $eavAttributeResource;
    }

    const ADMIN_RESOURCE = 'Company_Module::aclrule';

    /**
     * Dispatch request
     *
     * @return \Magento\Framework\Controller\ResultInterface|ResponseInterface
     * @throws \Magento\Framework\Exception\NotFoundException
     */
    public function execute()
    {
        $result = $this->resultFactory->create(ResultFactory::TYPE_JSON);

        $responseData = [
            'error' => true
        ];

        try {
            $attribute               = $this->eavAttributeRepository->get('catalog_product', $this->_request->getParam('attributeId', null));
            $responseData['error']   = false;
            $responseData['options'] = $attribute->getSource()->getAllOptions();
        } catch (\Exception $e) {
        }

        return $result->setData($responseData);
    }
}

This is by no means perfect and needs a bit work (hardcoded values, perhaps moving the ajax to separate file etc.), but it should give you pretty good overview of such a feature. If you already have the options for select B loaded somewhere, just remove the ajax call and write your logic there.

Documentation is a good read about how two components can communicate with each other.

1
  • Thanks for the detailed answer I'll take a look to it and if it works will mark it as resolved Commented Sep 27, 2017 at 14:15
0

app/code/VendoreName/ModuleName/view/adminhtml/ui_component

ui_formname.xml

<form>
    ...............................................................................................................
    ...............................................................................................................

    <fieldset name="dynamic_data">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="collapsible" xsi:type="boolean">false</item>
                <item name="label" xsi:type="string" translate="true">Dynamic Options</item>
                <item name="sortOrder" xsi:type="number">10</item>
            </item>
        </argument>
        <field name="max_email_send">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">VendoreName\ModuleName\Model\Config\Source\MaximumEmailSend</item>
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="number">10</item>
                    <item name="dataType" xsi:type="string">string</item>
                    <item name="component" xsi:type="string">VendoreName_ModuleName/js/form/element/max-email-send</item>
                    <item name="label" xsi:type="string" translate="true">How Many Time Send Email</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="source" xsi:type="string">max_email_send</item>
                    <item name="dataScope" xsi:type="string">max_email_send</item>
                </item>
            </argument>
        </field>
        <field name="coupon_code_send">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="label" xsi:type="string">Which Email Send Coupon Code</item>
                    <item name="visible" xsi:type="boolean">true</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="formElement" xsi:type="string">select</item>
                    <item name="sortOrder" xsi:type="number">20</item>
                </item>
            </argument>
        </field>
        <container name="custom_tab_container">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="string">1</item>
                </item>
            </argument>
            <htmlContent name="html_content">
                <argument name="block" xsi:type="object">VendoreName\ModuleName\Block\Adminhtml\SetParamsToJs</argument>
            </htmlContent>
        </container>
    </fieldset>
</form>

app/code/VendoreName/ModuleName/Model/Config/Source

MaximumEmailSend.php

<?php

namespace VendoreName\ModuleName\Model\Config\Source;

class MaximumEmailSend implements \Magento\Framework\Option\ArrayInterface
{
    public function getOptionArray()
    {
        $options = [];
        for ($i = 1; $i <= 10; $i++) {
            $options[$i] = (__($i));
        }
        return $options;
    }

    public function getAllOptions()
    {
        $res = $this->getOptions();
        array_unshift($res, ['value' => '', 'label' => '']);
        return $res;
    }

    public function getOptions()
    {
        $res = [];
        foreach ($this->getOptionArray() as $index => $value) {
            $res[] = ['value' => $index, 'label' => $value];
        }
        return $res;
    }

    public function toOptionArray()
    {
        return $this->getOptions();
    }

}

app/code/VendoreName/ModuleName/view/adminhtml/web/js/form/element

max-email-send.js

define([
    'jquery',
    'Magento_Ui/js/form/element/select',
    'uiRegistry'
], function ($, Select, uiRegistry) {
    var self;

    return Select.extend({
        initialize: function () {
            self = this;
            this._super();

            var statusVal = this.value();

            setTimeout(function(){
                if (statusVal) {
                    $.ajax({
                        url: window.optionAjaxUrl,
                        type: 'post',
                        dataType: 'json',
                        cache: false,
                        showLoader: true,
                        data: {attributeId: statusVal}
                    }).
                    done(function (response) {
                        if (!response.error) {
                            uiRegistry.get('ui_formname.ui_formname.dynamic_data.coupon_code_send').
                            options(response.options);
                        }
                    });
                }
            }, 800);

            self.value.subscribe(function () {
                self.updateValueOptions();
            });

            return this;
        },

        /**
         * Update options in value select.
         */
        updateValueOptions: function () {


            if (self.value()) {
                $.ajax({
                    url: window.optionAjaxUrl,
                    type: 'post',
                    dataType: 'json',
                    cache: false,
                    showLoader: true,
                    data: {attributeId: self.value()}
                }).
                done(function (response) {
                    if (!response.error) {
                        uiRegistry.get('ui_formname.ui_formname.dynamic_data.coupon_code_send').
                        options(response.options);
                    }
                });
            }
            else {
                uiRegistry.get('ui_formname.ui_formname.dynamic_data.coupon_code_send').options([]);
            }
        }
    });
});

app/code/VendoreName/ModuleName/Block/Adminhtml

SetParamsToJs.php

<?php

namespace VendoreName\ModuleName\Block\Adminhtml;

class SetParamsToJs extends \Magento\Backend\Block\Template
{
    /**
     * Block template.
     *
     * @var string
     */
    protected $_template = 'set_params.phtml';

}

app/code/VendoreName/ModuleName/view/adminhtml/templates

set_params.phtml

<script type="text/javascript">

    window.optionAjaxUrl = "<?php echo $block->getUrl('adminroutename/index/loadoptions'); ?>";

</script>

app/code/VendoreName/ModuleName/Controller/Adminhtml/Index

LoadOptions.php

<?php

namespace VendoreName\ModuleName\Controller\Adminhtml\Index;

use Magento\Framework\Controller\ResultFactory;

class LoadOptions extends \Magento\Backend\App\Action
{
    protected $resultPageFactory;

    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Framework\View\Result\PageFactory $resultPageFactory
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
    }

    public function execute()
    {
        $data = $this->getRequest()->getPostValue();
        $result = $this->resultFactory->create(ResultFactory::TYPE_JSON);
        $responseData = [
            'error' => true,
        ];
        if ($data['attributeId']) {
            try {
                $responseData['error'] = false;
                $options = [];
                for ($i = 1; $i <= $data['attributeId']; $i++) {
                    //$options[] = ['label' => (__($i)), 'value' => (__($i))];
                    $options[] = ['label' => (__($i)), 'value' => $i];
                }
                $responseData['options'] = $options;
            } catch (\Exception $e) {
                $responseData['options'] = [];
            }
        }
        return $result->setData($responseData);
    }

}

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.