Magento 2.1 Làm cách nào để tạo tùy chỉnh trường thành phần biểu mẫu phụ thuộc vào giá trị trường khác?


13

Tôi có một lựa chọn trong đó có một số tùy chọn. Một trong số chúng sẽ có một số trường phụ thuộc vào giá trị, một trường khác sẽ ẩn. Tôi đã sao chép và mở rộng js thành phần cho lĩnh vực của mình nhưng nó không hoạt động hoặc tôi đã làm sai. Thành phần Ui hỗ trợ tính năng này? Làm thế nào tôi có thể đạt được điều này?

Dưới đây là những gì tôi đã làm:

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

Câu trả lời:


26

Hãy thử điều này ( Lưu ý : Đừng quên thay thế dòng "Không gian tên" và dòng "ModuleName" bằng các giá trị của bạn):

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

Ở đâu:

  • Khả năng hiển thị các phần tử con được đặt theo mặc định là false;
  • Các visibleValue- là field1giá trị khi yếu tố nên được hiển thị;

Không gian tên \ ModuleName \ Model \ Config \ Source \ Tùy chọn

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

ứng dụng / mã / 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();
        },
    });
});

Kết quả:

Giá trị 0 được chọn: Giá trị 0 được chọn

Giá trị 1 được chọn: Giá trị 1 được chọn

Giá trị 2 được chọn: Giá trị 2 được chọn

Giá trị 3 được chọn: Giá trị 3 được chọn

PS: Có thể nó không phải là giải pháp tốt nhất, nhưng nó sẽ giúp bạn


onUpdate đang hoạt động tốt, nhưng làm thế nào để tạo onLoad? Làm thế nào để có được trường1.value?
zhartaunik

@zhartaunik Tôi nghĩ bạn nên sử dụng initializephương pháp trong trường hợp của bạn bởi vì phần tử không có onLoadphương pháp. Bạn có thể nhận bất kỳ giá trị trường nào ở bất kỳ nơi nào từ sổ đăng ký bằng khóa chỉ mục đầu vào : uiRegistry.get('index = field1'). Trong trường hợp bạn có nhiều câu hỏi hơn, xin vui lòng, giải quyết cho tôi bằng skype (sarj1989) sẽ dễ dàng hơn để giao tiếp bằng tiếng Nga.
Siarhey Uchukhlebau

Cảm ơn @Siarhey. Tôi quyết định sử dụng khởi tạo. this ._super, hơn xác minh cần thiết.
zhartaunik

1
Tôi không thể nhận giá trị trường khi tôi đang sử dụng giá trị phương thức khởi tạo là "không xác định".
Saurabh Taletiya

1
@Siarhey Uchukhlebau Tôi có thể thêm hộp kiểm thay thế không?
Juliano Vargas

8

Giải pháp được đề xuất bởi Magentix sẽ thỉnh thoảng xuất hiện lỗi khi sử dụng khởi tạo. Nó phụ thuộc vào thời gian để trình duyệt của bạn hiển thị các thành phần. Để khắc phục, bạn có thể sử dụng setTimeout.

Xem mã dưới đây:

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

Nó hoạt động đúng.
Dhaduk Mitesh

+1 từ phía tôi. Không có công việc nào khác nhưng điều này đã làm công việc của tôi.
ẩn danh

7

Đây là một câu hỏi cũ với nhiều câu trả lời hoạt động, tuy nhiên tôi đã phát hiện ra một giải pháp sử dụng những gì Magento cung cấp (kể từ 2.1.0) mà không cần phải mở rộng các thành phần. Vì nhiều câu hỏi đã được đánh dấu là trùng lặp và được hướng dẫn ở đây, tôi nghĩ sẽ có ích khi cung cấp một số thông tin về tùy chọn này.

Tất cả các thành phần ui thành phần mở rộng Magento_Ui/js/form/element/abstract.jsđều có switcherConfigsẵn một cài đặt cho các mục đích như ẩn / hiển thị các thành phần cũng như các hành động khác. Thành switcherphần có thể được tìm thấy tại Magento_Ui / js / form / switcher cho người tò mò. Bạn có thể tìm thấy các ví dụ về nó đang được sử dụng trong sales_rule_form.xmlcatalog_rule_form.xml . Tất nhiên, nếu bạn đang sử dụng thành phần tùy chỉnh của riêng mình, bạn vẫn có thể sử dụng thành phần này miễn là thành phần của bạn cuối cùng sẽ mở rộng abstract, dường như là trường hợp dựa trên mã ví dụ được cung cấp trong câu hỏi.

Bây giờ cho một ví dụ cụ thể hơn để trả lời câu hỏi ban đầu.

Trong Namespace/ModuleName/view/adminhtml/ui_component/your_entity_form.xmlbạn chỉ cần thêm phần sau vào trường settingskiểm soát (tức là trường xác định trường nào bị ẩn / hiển thị). Trong ví dụ của bạn, điều này sẽ là 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>

Hãy phá vỡ nó một chút. Thành switcherphần này chứa một mảng trong rulesđó là những gì chúng ta đang xây dựng ở đây. Mỗi cái <rule>có một tên là một số trong ví dụ này. Tên này là khóa / chỉ mục mảng cho mặt hàng này. Chúng tôi đang sử dụng số làm chỉ mục mảng. Chuỗi cũng nên hoạt động nhưng tôi đã không kiểm tra lý thuyết này . CẬP NHẬT - Như được đề cập bởi @ChristopheFerreboeuf trong các bình luận, chuỗi không hoạt động ở đây. Đây là các mảng và nên bắt đầu bằng 0, không phải chuỗi hoặc 1.

Bên trong mỗi rulechúng ta vượt qua hai đối số.

  1. value- Đây là giá trị field1sẽ kích hoạt actionsđịnh nghĩa dưới đây.
  2. actions- Ở đây chúng tôi có một mảng khác. Đây là những hành động được kích hoạt khi các điều kiện của quy tắc này được đáp ứng. Một lần nữa, actiontên của mỗi chỉ là chỉ mục mảng / khóa của mục đó.

Bây giờ mỗi cái actioncũng có hai đối số (với thứ 3 tùy chọn).

  1. target- Đây là yếu tố bạn muốn thao tác dưới hành động này. Nếu bạn không quen với cách các tên thành phần ui_component được tạo trong Magento, bạn có thể xem bài viết của Alan Storm . Về cơ bản, nó giống như {component_name}.{component_name}.{fieldset_name}.{field_name}trong ví dụ này.
  2. callback- Đây là hành động được thực hiện trên các đề cập ở trên target. Cuộc gọi lại này phải là một chức năng có sẵn trên phần tử được nhắm mục tiêu. Ví dụ của chúng tôi sử dụng hideshow. Đây là nơi bạn có thể bắt đầu mở rộng về chức năng có sẵn. Các catalog_rule_form.xmlví dụ tôi đã đề cập trước đó sử dụng setValidationnếu bạn muốn xem một ví dụ khác.
  3. Bạn cũng có thể thêm <params>vào bất kỳ actioncuộc gọi nào cho họ. Bạn có thể thấy điều này trong catalog_rule_form.xmlví dụ là tốt.

Cuối cùng mục cuối cùng bên trong switcherConfig<enabled>true</enabled>. Điều này khá đơn giản, đó là Boolean để bật / tắt chức năng trình chuyển đổi mà chúng ta vừa thực hiện.

Và chúng ta đã hoàn thành. Vì vậy, sử dụng ví dụ ở trên những gì bạn sẽ thấy là trường field2Depend1được hiển thị nếu bạn chọn một tùy chọn có giá trị 2trên field1field3Depend1được hiển thị nếu bạn chọn một tùy chọn có giá trị 3.

Tôi đã kiểm tra ví dụ này bằng cách chỉ sử dụng hideshowtrên một trường bắt buộc và nó dường như có thể nhìn thấy để xác nhận. Nói cách khác, nếu field2Depend1được yêu cầu, nó sẽ chỉ được yêu cầu khi nhìn thấy. Không cần cấu hình thêm để làm việc.

Hy vọng điều này cung cấp một số trợ giúp cho bất cứ ai đang tìm kiếm một giải pháp vượt trội hơn.


1
"Chuỗi cũng nên hoạt động nhưng tôi đã không kiểm tra lý thuyết này." Tôi đã vô tình kiểm tra và nó không ... Các hành động là mảng quy tắc cần bắt đầu bằng hành động 0 hoặc quy tắc 0 chứ không phải 1 hoặc chuỗi ...
Barshe Ferreboeuf

6

Có rất nhiều câu trả lời cho câu hỏi này, nhưng hầu hết trong số họ đều đưa ra các giả định về việc liệu uiRegistry đã được tải đầy đủ hay sử dụng setTimeoutđể xóa ngăn xếp cuộc gọi và chờ đợi sự kiện tiếp theo (theo ý kiến ​​của tôi vẫn là sai làm điều đó - vì bạn không thể chắc chắn khi các thành phần ui khác đã tải - hãy sửa tôi nếu tôi sai).

Đầu tiên, tất nhiên, thêm thành phần JS tùy chỉnh của bạn vào cấu hình trường (xem các câu trả lời khác để biết chi tiết):

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

Sau đó, đây là thành phần UI tùy chỉnh ẩn hoặc hiển thị các trường phụ thuộc - với các bình luận để giải thích những gì đang xảy ra.

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

Nếu bạn gặp lỗi như Field is Undefinedkhi khởi tạo trường hiển thị, hãy sử dụng setTimeout()để tải các trường phụ thuộc đó:

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

Thay vì setTimeout, thay vào đó, hãy sử dụng phương pháp không đồng bộ để nhận phụ thuộc:uiRegistry.get('q', function(field) { ... }));
Erfan

Ngay lập tức gợi ý trong bình luận và bỏ phiếu cho câu trả lời của tôi, bạn có thể Đăng lên đây câu trả lời của bạn, Đây không phải là cách để dành bất kỳ câu trả lời nào, Bạn chỉ đề xuất cách khác, câu trả lời của tôi không sai. @Erfan. phiếu bầu của bạn làm cho ấn tượng sai.
Ronak Chauhan

@RonakChauhan - Đồng ý về điểm !!! Câu trả lời của bạn không sai, những người khác nhau có ý kiến, đề xuất và giải pháp khác nhau. Câu trả lời của bạn cũng đúng !!
Manthan Dave

Đợi một giây để khởi tạo và chặn khởi tạo khá rõ ràng là cách làm sai. Làm thế nào để bạn biết phụ thuộc của bạn sẽ được tải trong một giây? Tại sao nó không phải là hai giây? Bạn đang đưa ra một giả định ở đây, tốt nhất nên tránh.
Erfan

Tôi chưa đặt 1 giây ở đây, tính bằng mili giây, SetTimeout () sẽ chỉ tải mã của tôi sau khi tải trang, và nếu bạn có câu trả lời của mình thì bạn có thể đăng nó. Bỏ phiếu cho câu trả lời của ai đó không phải là cách để chứng minh bạn đúng! @Erfan
Ronak Chauhan

2

Thành phần tùy chỉnh với 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;
        }
    });
});

nó hiển thị "trường không xác định" sau khi sử dụng chức năng khởi tạo.
Hoàng tử Patel

1
Sử dụng setTimeout()trong fieldDepend()vì phụ thuộc chưa được tải.
Ronak Chauhan

1

Có một số cách để xử lý các phụ thuộc trường, đối với thả xuống Có / Không đơn giản, hộp kiểm hoặc trình chuyển đổi, bạn có thể sử dụng importshoặc exportsliên kết các thuộc tính trong Magento 2. Giải pháp được thảo luận chi tiết tại đây: Các trường phụ thuộc trong các thành phần UI trong Magento 2 không có Javascript cho các trường boolean :

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

Để xử lý loại giá trị khác, chẳng hạn như phụ thuộc vào danh sách các giá trị trong danh sách thả xuống hoặc mặc dù không thể, giá trị của trường đầu vào, bạn có thể sử dụng switcherConfig. Kiểm tra các trường phụ thuộc ở dạng ui-thành phần trong Magento 2 mà không có Javascript để biết thông tin.

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

Hai quy tắc trên, xử lý khá nhiều thứ bằng cách sử dụng cấu hình XML. Đối với các quy tắc phức tạp hơn, bạn cũng có thể sử dụng JavaScript.

Mỗi trường trong biểu mẫu thành phần UI là một thành phần có thể được mở rộng bằng cách sử dụng componentthuộc tính cho <field component="path to your js" ...>...</field>. Sau đó, bạn có thể sử dụng trường data.configđể truyền thêm thông tin cho thành phần, trong trường hợp thành phần đó là chung và được sử dụng lại ở nhiều nơi, kết hợp với thuộc tính importshoặc exportsliên kết để truyền giá trị cho các phương thức hoặc phương thức quan sát.

Để biết thêm thông tin về các thuộc tính liên kết, bạn có thể kiểm tra các thuộc tính Liên kết của các thành phần UI


0

Chỉ trong trường hợp ai đó đấu tranh với giải pháp Erfan , bạn phải chuyển toàn bộ đường dẫn đến các trường trong dependentFieldNames, ví dụ:

       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'
    ],

Tôi không chắc tại sao form_name phải được 2 lần, nhưng điều này đã làm việc cho tôi.

Để gỡ lỗi tôi này đặt console.log(query);tại static/adminhtml/Magento/backend/en_US/Magento_Ui/js/lib/registry/registry.js223 đường (các get () chức năng ngay trước this._addRequest(query, callback))

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.