Magento 2.1如何创建表单组件字段自定义依赖于另一个字段值?


13

我有一个字段选择,其中有一些选项。其中一个将有一些字段取决于值,另一个字段将被隐藏。我已经为我的领域复制并扩展了组件js,但是没有用,或者我做错了方法。ui组件支持此功能吗?我该如何实现?

以下是我所做的:

<field name="field1">
    <argument name="data" xsi:type="array">
        <item name="options" xsi:type="object">Namespace\ModuleName\Model\Config\Source\Options</item>
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">Field name</item>
            <item name="visible" xsi:type="boolean">true</item>
            <item name="dataType" xsi:type="string">number</item>
            <item name="formElement" xsi:type="string">select</item>
            <item name="source" xsi:type="string">item</item>
            <item name="dataScope" xsi:type="string">field1</item>
            <item name="component" xsi:type="string">Pathto/js/form/element/options</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
        </item>
    </argument>
</field>

<field name="field2Depend1"></field>
<field name="field3Depend1"></field>

jsComponent js/form/element/options

define([
    'underscore',
    'uiRegistry',
    'Magento_Ui/js/form/element/select',
    'Magento_Ui/js/modal/modal'
], function (_, uiRegistry, select) {
    'use strict';

    return select.extend({

        onChange: function () {
            this.enableDisableFields();
        },

        /**
         * Enable/disable fields on Coupons tab
         */
        enableDisableFields: function () {
            // code check field
        }
    });
});

Answers:


26

尝试以下操作(注意:不要忘记用您的值替换“名称空间”行和“ ModuleName”行):

<field name="field1">
    <argument name="data" xsi:type="array">
        <item name="options" xsi:type="object">Namespace\ModuleName\Model\Config\Source\Options</item>
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string" translate="true">Parent Option</item>
            <item name="component" xsi:type="string">Namespace_ModuleName/js/form/element/options</item>
            <item name="visible" xsi:type="boolean">true</item>
            <item name="dataType" xsi:type="string">number</item>
            <item name="formElement" xsi:type="string">select</item>
            <item name="source" xsi:type="string">item</item>
            <item name="dataScope" xsi:type="string">field1</item>
            <item name="sortOrder" xsi:type="number">210</item>
            <item name="validation" xsi:type="array">
                <item name="required-entry" xsi:type="boolean">true</item>
            </item>
        </item>
    </argument>
</field>

<field name="field2Depend1">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string">Field 1</item>
            <item name="dataType" xsi:type="string">text</item>
            <item name="formElement" xsi:type="string">input</item>
            <item name="source" xsi:type="string">item</item>
            <item name="sortOrder" xsi:type="number">220</item>
            <item name="breakLine" xsi:type="boolean">true</item>
            <item name="visibleValue" xsi:type="string">2</item>
            <item name="visible" xsi:type="boolean">false</item>
        </item>
    </argument>
</field>
<field name="field3Depend1">
    <argument name="data" xsi:type="array">
        <item name="config" xsi:type="array">
            <item name="label" xsi:type="string">Field 2</item>
            <item name="dataType" xsi:type="string">text</item>
            <item name="formElement" xsi:type="string">input</item>
            <item name="source" xsi:type="string">item</item>
            <item name="sortOrder" xsi:type="number">230</item>
            <item name="breakLine" xsi:type="boolean">true</item>
            <item name="visibleValue" xsi:type="string">0</item>
            <item name="visible" xsi:type="boolean">false</item>
        </item>
    </argument>
</field>

哪里:

  • 子元素的可见性默认设置为false;
  • 当元素应可见时,visibleValue-是field1值;

命名空间\ ModuleName \ Model \ Config \ Source \ Options

namespace Namespace\ModuleName\Model\Config\Source;

use Magento\Framework\Option\ArrayInterface;

class Options implements ArrayInterface
{
    /**
     * @return array
     */
    public function toOptionArray()
    {
        $options = [
            0 => [
                'label' => 'Please select',
                'value' => 0
            ],
            1 => [
                'label' => 'Option 1',
                'value' => 1
            ],
            2  => [
                'label' => 'Option 2',
                'value' => 2
            ],
            3 => [
                'label' => 'Option 3',
                'value' => 3
            ],
        ];

        return $options;
    }
}

app / code / Namespace / ModuleName / view / adminhtml / web / js / form / element / options.js

define([
    'underscore',
    'uiRegistry',
    'Magento_Ui/js/form/element/select',
    'Magento_Ui/js/modal/modal'
], function (_, uiRegistry, select, modal) {
    'use strict';

    return select.extend({

        /**
         * On value change handler.
         *
         * @param {String} value
         */
        onUpdate: function (value) {
            console.log('Selected Value: ' + value);

            var field1 = uiRegistry.get('index = field2Depend1');
            if (field1.visibleValue == value) {
                field1.show();
            } else {
                field1.hide();
            }

            var field2 = uiRegistry.get('index = field3Depend1');
            if (field2.visibleValue == value) {
                field2.show();
            } else {
                field2.hide();
            }

            return this._super();
        },
    });
});

结果:

选择了值0: 值0已选择

选择了值1: 值1已选择

选择了值2: 值2已选择

选择了值3: 值3已选择

PS:可能这不是最好的解决方案,但它可以为您提供帮助


onUpdate运作良好,但如何制作onLoad?如何获得field1.value?
zhartaunik '16

@zhartaunik我认为您应该initialize在这种情况下使用该方法,因为ui-element没有onLoad方法。您可以使用输入索引键:从注册表中的任何位置获取任何字段值uiRegistry.get('index = field1')。如果您还有其他问题,请在skype(sarj1989)中与我联系,以俄语进行交流会更容易。
Siarhey Uchukhlebau,2016年

谢谢@Siarhey。我决定使用初始化。this._super,而不是添加必要的验证。
zhartaunik '16

1
当我使用初始化方法的值是“未定义”时,我无法获取字段值。
Saurabh Taletiya '17

1
@Siarhey Uchukhlebau我可以改为添加复选框吗?
朱利诺·巴尔加斯

8

Magentix建议的解决方案在使用初始化时会不时抛出错误。这取决于您的浏览器呈现组件所花费的时间。为了解决它,您可以使用setTimeout。

请参见下面的代码:

define([
    'underscore',
    'uiRegistry',
    'Magento_Ui/js/form/element/select',
    'Magento_Ui/js/modal/modal'
], function (_, uiRegistry, select, modal) {
    'use strict';

    return select.extend({

        /**
         * Extends instance with defaults, extends config with formatted values
         *     and options, and invokes initialize method of AbstractElement class.
         *     If instance's 'customEntry' property is set to true, calls 'initInput'
         */
        initialize: function () {
            this._super();

            this.resetVisibility();

            return this;
        },

        toggleVisibilityOnRender: function (visibility, time) {
            var field = uiRegistry.get('index = field_to_toggle');
            if(field !== undefined) {
                if(visibility == 1) {
                    field.show();
                } else {
                    field.hide();
                }

                return;
            }
            else {
                var self = this;
                setTimeout(function() {
                    self.toggleVisibilityOnRender(visibility, time);
                }, time);
            }
        },

        /**
         * On value change handler.
         *
         * @param {String} value
         */
        onUpdate: function (value) {
            if (value == 1) {
                this.showField();
            } else {
                this.hideField();
            }
            return this._super();
        },

        resetVisibility: function () {
            if (this.value() == 1) {
                this.showField();
            } else {
                this.hideField();
            }
        },

        showField: function () {
            this.toggleVisibilityOnRender(1, 1000);

        },

        hideField: function () {
            this.toggleVisibilityOnRender(0, 1000);
        }
    });
});

它的工作正常。
Dhaduk Mitesh

从我这边+1。没有其他作品,但这是我的工作。
匿名

7

这是一个有多个答案的老问题,但是我发现了使用Magento提供的解决方案(从2.1.0版本开始),而无需扩展组件。由于多个问题被标记为重复并直接指向此处,因此我认为提供有关此选项的一些信息将是有益的。

所有扩展的表单元素ui组件Magento_Ui/js/form/element/abstract.js都具有switcherConfig可用于设置目的的设置,例如隐藏/显示元素以及其他操作。出于好奇,switcher可以在Magento_Ui / js / form / switcher中找到该组件。您可以在sales_rule_form.xmlcatalog_rule_form.xml中找到使用它的示例。当然,如果您已经在使用自己的自定义组件,那么只要您的组件最终abstract得以扩展,就可以使用它,根据问题中提供的示例代码,情况似乎确实如此。

现在为回答原始问题提供一个更具体的示例。

Namespace/ModuleName/view/adminhtml/ui_component/your_entity_form.xml您只需要将以下内容添加到进行settings控制的字段(即确定哪些字段是隐藏/可见的字段)中即可。在您的示例中,它将为field1

<field name="field1">
    <argument name="data" xsi:type="array">
        ...
    </argument>
    <settings>
        <switcherConfig>
            <rules>
                <rule name="0">
                    <value>2</value>
                    <actions>
                        <action name="0">
                            <target>your_entity_form.your_entity_form.entity_information.field2Depend1</target>
                            <callback>show</callback>
                        </action>
                        <action name="1">
                            <target>your_entity_form.your_entity_form.entity_information.field3Depend1</target>
                            <callback>hide</callback>
                        </action>
                    </actions>
                </rule>
                <rule name="1">
                    <value>3</value>
                    <actions>
                        <action name="0">
                            <target>your_entity_form.your_entity_form.entity_information.field2Depend1</target>
                            <callback>hide</callback>
                        </action>
                        <action name="1">
                            <target>your_entity_form.your_entity_form.entity_information.field3Depend1</target>
                            <callback>show</callback>
                        </action>
                    </actions>
                </rule>
            </rules>
            <enabled>true</enabled>
        </switcherConfig>
    </settings>
</field>

让我们分解一下。该switcher组件包含一个数组,rules这就是我们在此处构建的。<rule>在此示例中,每个名称都有一个数字。此名称是该项目的阵列键/索引。我们使用数字作为数组索引。字符串也应该起作用,但是我还没测试过这个理论更新 -正如@ChristopheFerreboeuf在评论中提到的那样,字符串在这里不起作用。这些是数组,应以开头0,而不是字符串或1。

在每个内部,rule我们传递两个参数。

  1. value-这是field1应该触发以下actions定义的值。
  2. actions-这里有另一个数组。这些是满足此规则条件时要触发的操作。同样,每个action的名称只是该项目的数组索引/键。

现在每个action参数也都有两个参数(带有可选的第3个参数)。

  1. target-这是您希望在此操作下操作的元素。如果您不熟悉Magento中ui_component元素名称的组成方式,则可以查看Alan Storm的文章。基本上{component_name}.{component_name}.{fieldset_name}.{field_name}在此示例中类似。
  2. callback-这是针对上述问题要采取的措施target。此回调应该是在目标元素上可用的函数。我们的示例使用hideshow。在这里,您可以开始扩展可用功能。该catalog_rule_form.xml例子中,我前面提到的用途setValidation,如果你希望看到一个不同的例子。
  3. 您也可以添加<params>到任何action需要它们的地方。您也可以在catalog_rule_form.xml示例中看到这一点。

最后,里面的最后一项switcherConfig<enabled>true</enabled>。这应该很简单,它是一个布尔值,用于启用/禁用我们刚刚实现的切换器功能。

我们完成了。因此,使用上面的你应该看到的例子是场field2Depend1,如果您选择使用值的选项显示2field1,并field3Depend1显示如果您选择与价值的选择3

我只测试使用这个例子hide,并show在需要的领域,它似乎把了解帐户进行验证。换句话说,如果field2Depend1需要,则仅在可见时才需要。无需进一步配置即可工作。

希望这对寻求更开箱即用的解决方案的人有所帮助。


1
“字符串也应该起作用,但是我还没有检验过这种理论。” 我不小心进行了测试,但它没有...操作是作为规则数组,需要以操作0或规则0而不是1或字符串
开头

6

这个问题有很多答案,但是其中大多数都假设uiRegistry是否已完全加载,或者用于setTimeout清除调用堆栈,并等待下一个eventloop(我认为这仍然是错误的处理方式)。这样做-因为您不确定其他ui组件何时加载-如果我错了请指正我)。

首先,当然,将您的自定义JS组件添加到字段配置中(有关详细信息,请参见其他答案):

<item name="component" xsi:type="string">Namespace_ModuleName/js/form/element/options</item>

然后,这是隐藏或显示相关字段的自定义UI组件-带有注释以解释发生了什么。

define([
    'underscore',
    'uiRegistry',
    'Magento_Ui/js/form/element/select'
], function (_, uiRegistry, select) {

    'use strict';

    return select.extend({

        /**
         * Array of field names that depend on the value of 
         * this UI component.
         */
        dependentFieldNames: [
            'my_field_name1',
            'my_field_name2'
        ],

        /**
         * Reference storage for dependent fields. We're caching this
         * because we don't want to query the UI registry so often.
         */
        dependentFields : [],

        /**
         * Initialize field component, and store a reference to the dependent fields.
         */
        initialize: function() {
            this._super();

            // We're creating a promise that resolves when we're sure that all our dependent
            // UI components have been loaded. We're also binding our callback because
            // we're making use of `this`
            uiRegistry.promise(this.dependentFieldNames).done(_.bind(function() {

                // Let's store the arguments (the UI Components we queried for) in our object
                this.dependentFields = arguments;

                // Set the initial visibility of our fields.
                this.processDependentFieldVisibility(parseInt(this.initialValue));
            }, this));
        },

        /**
         * On value change handler.
         *
         * @param {String} value
         */
        onUpdate: function (value) {
            // We're calling parseInt, because in JS "0" evaluates to True
            this.processDependentFieldVisibility(parseInt(value));
            return this._super();
        },

        /**
         * Shows or hides dependent fields.
         *
         * @param visibility
         */
        processDependentFieldVisibility: function (visibility) {
            var method = 'hide';
            if (visibility) {
                method = 'show';
            }

            // Underscore's invoke, calls the passed method on all the objects in our array
            _.invoke(this.dependentFields, method);
        }
    });
});

5

如果您Field is Undefined在初始化字段可见性时遇到错误,请使用setTimeout()加载依赖的字段:

fieldDepend: function (value) {
     setTimeout(function(){ 
        var field1 = uiRegistry.get('index = field2');

        if (field1.visibleValue == value) {
               field1.show();
        } else {
               field1.hide();
        }

       var field2 = uiRegistry.get('index = field3');

        if (field2.visibleValue == value) {
              field2.show();
        } else {
              field2.hide();
        }    
     }, 1);
     return this._super();
},

代替setTimeout,使用异步方法获取依赖项:uiRegistry.get('q', function(field) { ... }));
Erfan

可以在评论中建议并拒绝我的答案,您可以在此处发布您的答案,这不是专门的答案,您只是在以不同的方式提出建议,我的答案没有错。@Erfan。您的不赞成票给人留下了错误的印象。
罗纳克·乔汉

@RonakChauhan-同意观点!您的答案不正确,不同的人有不同的意见,建议和解决方案。您的答案也是正确的!
Manthan Dave

等待一秒钟进行初始化,然后阻止初始化显然是错误的方法。您甚至怎么知道一秒钟就会加载您的依赖项?为什么不两秒钟呢?您在这里做一个假设,最好避免。
Erfan

我没有在这里设置1秒,它以毫秒为单位,SetTimeout()只会在加载页面后加载我的代码,如果您有答案,则可以发布它。否决某人的答案不是证明自己正确的方法!@Erfan
Ronak Chauhan

2

具有init的自定义组件:

define([
    'underscore',
    'uiRegistry',
    'Magento_Ui/js/form/element/select',
    'Magento_Ui/js/modal/modal'
], function (_, uiRegistry, select, modal) {
    'use strict';

    return select.extend({

        /**
         * Init
         */
        initialize: function () {
            this._super();

            this.fieldDepend(this.value());

            return this;
        },

        /**
         * On value change handler.
         *
         * @param {String} value
         */
        onUpdate: function (value) {
            this.fieldDepend(value);

            return this._super();
        },

        /**
         * Update field dependency
         *
         * @param {String} value
         */
        fieldDepend: function (value) {
            var field = uiRegistry.get('index = field_to_toggle');

            if (value == 'xxxxx') {
                field.show();
            } else {
                field.hide();
            }

            return this;
        }
    });
});

使用初始化函数后显示“字段未定义”。
帕特尔王子(Prince Patel)

1
用于setTimeout()fieldDepend()因为还没有加载depended。
罗纳克·乔汉

1

万一有人在使用Erfan解决方案时遇到困难,您必须将完整路径传递给中的字段dependentFieldNames,例如:

       dependentFieldNames: [
        'form_name.form_name.fieldset.field_name',
        'form_name.form_name.fieldset.field_name1',
        'form_name.form_name.fieldset.field_name2',
        'form_name.form_name.fieldset.field_name3'
    ],

我不确定为什么form_name必须是2次,但这对我有用。

为了调试它,我console.log(query);static/adminhtml/Magento/backend/en_US/Magento_Ui/js/lib/registry/registry.js第223行(get()函数在之前this._addRequest(query, callback)


1

有几种处理字段相关性的方法,对于简单的Yes / No下拉菜单,复选框或切换器,您可以使用Magento 2中的importsexports链接属性。此处详细讨论该解决方案:Magento中UI组件形式的相关字段2不带Javascript的布尔字段

<!-- In the parent field <settings>...</settings> -->
<exports>
    <link name="checked">${$.parentName}.description:disabled</link>
</exports>

<!-- or -->

<!-- In the dependent field <settings>...</settings> -->
<imports>
    <link name="disabled">${$.parentName}.is_active:checked</link>
</imports>

要处理其他类型的值,例如对下拉列表中的值列表的依赖关系或输入字段的值(尽管不太可能),可以使用switcherConfig在不使用Javascript的Magento 2中,以ui组件形式检查相关字段,以获取信息。

<switcherConfig>
    <rules>
        <rule name="0">
            <value>list</value><!-- Actions defined will be trigger when the current selected field value matches the value defined here-->
            <actions>
                <action name="0">
                    <target>hs_xml_dependentfield_model_form.hs_xml_dependentfield_model_form.general.list</target>
                    <callback>visible</callback>
                    <params>
                        <param name="0" xsi:type="boolean">true</param>
                    </params>
                </action>
                <action name="1">
                    <target>hs_xml_dependentfield_model_form.hs_xml_dependentfield_model_form.general.hex_code</target>
                    <callback>visible</callback>
                    <params>
                        <param name="0" xsi:type="boolean">true</param>
                    </params>
                </action>
            </actions>
        </rule>
        ...
    </rules>
    <enabled>true</enabled>
</switcherConfig>

以上2条规则使用XML配置处理了几乎所有内容。对于更复杂的规则,您也可以使用JavaScript。

UI组件表单中的每个字段都是一个组件,可以使用的component属性进行扩展<field component="path to your js" ...>...</field>。然后data.config,如果该组件是通用的并在多个地方重复使用,则可以使用该字段将更多信息传递给该组件,并与importsexports链接属性组合以将值传递给可观察对象或方法。

有关链接属性的更多信息,可以检查UI组件的链接属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.