Magento 2.1別のフィールド値に依存するカスタムのフォームコンポーネントフィールドを作成するにはどうすればよいですか?


13

いくつかのオプションがある1つのフィールド選択があります。それらの1つには、値に依存するいくつかのフィールドがあり、別のフィールドは非表示になります。私のフィールド用にコンポーネント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
        }
    });
});

回答:


26

これを試してください(:「Namespace」行と「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要素が可視であるべき値。

Namespace \ 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 2016

@zhartaunik initializeui-elementにonLoadメソッドがないため、あなたはあなたのケースでメソッドを使うべきだと思います。入力インデックスキーを使用して、レジストリから任意の場所の任意のフィールド値を取得できますuiRegistry.get('index = field1')。さらに質問がある場合は、スカイプ(sarj1989)で私に連絡してください。ロシア語でのコミュニケーションが容易になります。
Siarhey Uchukhlebau

@Siarheyに感謝します。初期化することにしました。this._super、必要な検証を追加します。
zhartaunik 2016

1
初期化メソッドの値が「未定義」の場合、フィールド値を取得できません。
Saurabh Taletiya

1
@Siarhey Uchukhlebau代わりにチェックボックスを追加できますか?
ジュリアーノバルガス

8

Magentixによって提案されたソリューションは、initializeを使用すると時々エラーをスローします。これは、ブラウザがコンポーネントをレンダリングするのにかかる時間に依存します。これを修正するには、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 2018年

私の側から+1。他の作品はありませんが、これは私の仕事をしました。
匿名の

7

これは古い質問であり、複数の回答が機能しますが、Magentoが提供するもの(2.1.0以降)を使用して、コンポーネントを拡張する必要なくソリューションを発見しました。複数の質問が重複としてマークされ、ここで指示されているので、このオプションに関する情報を提供することは有益だと思いました。

拡張するすべてのフォーム要素のUIコンポーネントにMagento_Ui/js/form/element/abstract.jsは、switcherConfig要素の非表示/表示やその他のアクションなどの目的に使用できる設定があります。switcher成分はで見つけることができMagento_Ui / JS /フォーム/スイッチャー好奇心のために。sales_rule_form.xmlおよびcatalog_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ではなく、で始まる必要があります。

それぞれの中でrule2つの引数を渡します。

  1. value-これは、以下field1actions定義をトリガーする値です。
  2. actions-ここに別の配列があります。これらは、このルールの条件が満たされたときにトリガーされるアクションです。繰り返しますが、各actionの名前はその項目の配列インデックス/キーにすぎません。

これで、それぞれactionに2つの引数があります(オプションの3番目)。

  1. target-これは、このアクションで操作したい要素です。Magentoでのui_component要素名の構成方法に詳しくない場合は、Alan Stormの記事をご覧ください。基本的に{component_name}.{component_name}.{fieldset_name}.{field_name}はこの例のようなものです。
  2. callback-上記の対処方法は次のとおりtargetです。このコールバックは、対象の要素で使用できる関数である必要があります。この例ではhideおよびを使用していshowます。ここから、利用可能な機能の拡張を開始できます。catalog_rule_form.xml例では、私は、以前の使用法を述べたsetValidation別の例を参照したい場合。
  3. それら<params>を必要actionとするものに追加することもできます。catalog_rule_form.xml例でも確認できます。

最後に、最後のアイテムswitcherConfig<enabled>true</enabled>です。これは非常に簡単なはずです。実装したスイッチャー機能を有効または無効にするブール値です。

これで完了です。だから、あなたが見るべきか、上記の例を使用すると、フィールドがあるfield2Depend1あなたが値を持つオプションを選択した場合、表示2上のfield1、そしてfield3Depend1あなたが値を持つオプションを選択した場合に表示しました3

必須フィールドのみhideを使用してこの例をテストshowしましたが、検証のために可視性が考慮されているようです。つまり、field2Depend1必要な場合は、表示されている場合にのみ必要です。それを機能させるために、さらに設定する必要はありません。

これがより独創的なソリューションを探している人に役立つことを願っています。


1
「ストリングも機能するはずですが、この理論はテストしていません。」私は誤ってテストしましたが、動作しません...アクションは、0のアクションまたは1のルールではなく0のルールで始まる必要があるルール配列です
Christophe Ferreboeuf

6

この質問には多くの答えがありますが、それらのほとんどは、uiRegistryが完全にロードされているかどうかを想定するかsetTimeout、コールスタックをクリアするために使用して、次のイベントループを待機します(私の意見では、これはまだ間違った方法です)それを行う-他の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。あなたの反対票は間違った印象を与えます。
Ronak Chauhan 2017

@RonakChauhan-ポイントで合意!!! あなたの答えは不正確ではありません、異なる人々は異なる意見、提案、解決策を持っています。あなたの答えも正しいです!
Manthan Dave 2017

初期化に1秒待機し、初期化をブロックすることは、明らかにそれを行うための間違った方法です。依存関係が1秒で読み込まれることをどうやって知るのですか?なぜ2秒にならないのですか?あなたはここで仮定をしている、それは避けた方がいい。
Erfan

ここでは1秒を設定していません。ミリ秒単位で、SetTimeout()はページをロードした後にコードをロードします。そして、答えがあればそれを投稿できます。誰かの回答に反対票を投じることは、自分を正しく証明する方法ではありません!@Erfan
Ronak Chauhan '29

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()
Ronak Chauhan 2017

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.js223行目(直前のget()関数this._addRequest(query, callback))を入力します。


1

フィールドの依存関係を処理する方法はいくつかあります。単純な[はい/いいえ]ドロップダウン、チェックボックスまたはスイッチャーの場合、Magento 2のプロパティimportsまたはexportsリンクプロパティを使用できます。解決策については、ここで詳しく説明します。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を使用してより多くの情報をコンポーネントに渡すことができます。コンポーネントが汎用であり、複数の場所で再利用され、importsまたはexportsリンクプロパティと組み合わせて、オブザーバブルまたはメソッドに値を渡すことができます。

リンクプロパティの詳細については、UIコンポーネントのリンクプロパティを確認できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.