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
        }
    });
});

답변:


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 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

추신 : 아마도 최상의 해결책은 아니지만 도움이 될 것입니다.


onUpdate가 제대로 작동하지만 onLoad를 만드는 방법은 무엇입니까? field1.value를 얻는 방법?
zhartaunik

@zhartaunik initializeui-element에는 onLoad방법 이 없기 때문에이 방법 을 사용해야한다고 생각합니다 . 입력 색인 키를 사용하여 레지스트리에서 임의의 위치에있는 필드 값을 얻을 수 있습니다 uiRegistry.get('index = field1'). 더 궁금한 점이 있으시면 skype (sarj1989)로 알려주십시오. 러시아어로 의사 소통하기가 더 쉬울 것입니다.
Siarhey Uchukhlebau

@Siarhey에게 감사합니다. 초기화를 사용하기로 결정했습니다. this._super, 필요한 확인을 추가하십시오.
zhartaunik

1
초기화 메소드 값을 사용하는 경우 필드 값을 가져올 수 없습니다 "정의되지 않음".
Saurabh Taletiya

1
@Siarhey Uchukhlebau 대신 확인란을 추가 할 수 있습니까?
Juliano Vargas

9

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 기준). 여러 질문이 중복으로 표시되고 여기에 지시되었으므로이 옵션에 대한 정보를 제공하는 것이 도움이 될 것이라고 생각했습니다.

확장되는 모든 form element 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에는 두 개의 인수가 있습니다 (선택 사항 인 세 번째).

  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.

난 단지 사용이 예제를 테스트 한 hideshow필요한 필드 확인을 위해 계정에 대한 가시성을하는 것처럼 보인다. 다시 말해, 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

의견을 제안하고 내 답변을 다운 투표 할 수 있습니다. 여기에 답변을 게시하십시오. 이것은 답변을 바치는 방법이 아닙니다. 당신은 다른 방법을 제안하고 있습니다. @ 에르 판 귀하의 다운 투표는 잘못된 인상을 남깁니다.
Ronak Chauhan

@RonakChauhan-포인트 합의 !!! 당신의 대답은 틀리지 않습니다, 다른 사람들은 다른 의견, 제안 및 솔루션을 가지고 있습니다. 당신의 대답도 정확합니다!
Manthan Dave

초기화를 1 초간 기다렸다가 초기화를 차단하는 것은 분명히 잘못된 방법입니다. 종속성이 1 초 안에로드 될 것임을 어떻게 알 수 있습니까? 왜 2 초가되지 않습니까? 여기서 가정을하는 것이 가장 좋습니다.
Erfan

여기에 1 초를 설정하지 않았습니다. 밀리 초 단위로 SetTimeout ()은 페이지를로드 한 후 내 코드를로드합니다. 답이 있으면 게시 할 수 있습니다. 누군가의 대답은 자신을 올바르게 증명하는 방법이 아닙니다! @Erfan
Chauhan

2

초기화 된 사용자 컴포넌트 :

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;
        }
    });
});

초기화 기능을 사용한 후 "필드가 정의되지 않았습니다"라는 메시지가 표시됩니다.
프린스 파텔

1
사용 setTimeout()fieldDepend()의존 된이 아직로드되지 않기 때문에.
Ronak Chauhan

2

필드 의존성을 처리하는 몇 가지 방법이 있습니다. 간단한 예 / 아니요 드롭 다운, 확인란 또는 스위처의 경우 Magento 2에서 속성을 사용 imports하거나 exports연결 속성을 사용할 수 있습니다 . 솔루션은 여기에서 자세히 설명합니다. Magento의 UI 구성 요소 양식의 종속 필드 부울 필드에 Javascript가없는 2 :

<!-- 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>

위의 두 규칙은 XML 구성을 사용하여 거의 모든 것을 처리합니다. 더 복잡한 규칙의 경우 JavaScript도 사용할 수 있습니다.

UI 구성 요소 양식의 각 필드는의 component속성을 사용하여 확장 할 수있는 구성 요소입니다 <field component="path to your js" ...>...</field>. 그런 다음 data.config구성 요소가 일반적이고 여러 위치에서 재사용되는 경우 imports또는 필드 를 사용하여 exports값을 관찰 가능 항목 또는 메서드에 전달하는 경우 필드 를 사용하여 추가 정보를 구성 요소 에 전달할 수 있습니다.

연결 속성에 대한 자세한 내용 은 UI 구성 요소의 연결 속성을 확인할 수 있습니다


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 배 여야하는지 잘 모르겠지만 이것이 효과가있었습니다.

이 I 넣어 디버깅하려면 console.log(query);에서 static/adminhtml/Magento/backend/en_US/Magento_Ui/js/lib/registry/registry.js(직전의 get () 함수 223번째 선 this._addRequest(query, callback))

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.