Magento 2.1 How do I create form component field custom depends on another field value?
Try this (Note: Don't forget to replace the line "Namespace" and the line "ModuleName" with your values):
<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>
Where:
- The child elements visibility is set by default as
false
; - The
visibleValue
- isfield1
value when element should be visible;
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();
},
});
});
Result:
Value 0 selected:
Value 1 selected:
Value 2 selected:
Value 3 selected:
PS: Possibly it not the best solution, but it shall help you
The solution suggested by Magentix will throw an error from time to time when using initialize. It depends on the time it takes for your browser to render the components. In order to fix it you could use setTimeout.
See the code below:
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);
}
});
});
This is an old question with multiple answers that work, however I have discovered a solution using what Magento provides (as of 2.1.0) without the need for extending components. As multiple questions have been marked as duplicate and directed here I thought it would be beneficial to provide some information on this option.
All form element ui components that extend Magento_Ui/js/form/element/abstract.js
have a switcherConfig
setting available for purposes such as hiding/showing elements as well as other actions. The switcher
component can be found at Magento_Ui/js/form/switcher for the curious. You can find examples of it being used in sales_rule_form.xml and catalog_rule_form.xml. Of course if you are using your own custom component already you can still use this as long as your component eventually extends abstract
which appears to be the case based on the example code provided in the question.
Now for a more specific example to answer the original question.
In Namespace/ModuleName/view/adminhtml/ui_component/your_entity_form.xml
you simply need to add the following to the field's settings
that does the controlling (i.e. the field that determines which fields are hidden/visible). In your example this would be 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>
Let's break it down a little. The switcher
component contains an array of rules
which is what we're building out here. Each <rule>
has a name which is a number in this example. This name is the array key/index for this item. We're using numbers as array indexes. Strings should work too but I haven't tested this theory.
UPDATE - As mentioned by @ChristopheFerreboeuf in the comments, strings to not work here. These are arrays and should start with 0
, not strings or 1.
Inside each rule
we pass two arguments.
value
- This is the value offield1
which should trigger theactions
defined below.actions
- Here we have another array. These are the actions to be triggered when this rule's conditions are met. Again, eachaction
's name is just the array index/key of that item.
Now each action
has two arguments as well (with an optional 3rd).
target
- This is the element you wish to manipulate under this action. If you aren't familiar with how ui_component element names are composed in Magento you can check out Alan Storm's article. It's basically something like{component_name}.{component_name}.{fieldset_name}.{field_name}
in this example.callback
- Here is the action to be taken on the above mentionedtarget
. This callback should be a function that is available on the element targeted. Our example useshide
andshow
. This is where you can start to expand on the functionality available. Thecatalog_rule_form.xml
example I mentioned earlier usessetValidation
if you wish to see a different example.- You can also add
<params>
to anyaction
that calls for them. You can see this in thecatalog_rule_form.xml
example as well.
Finally the last item inside switcherConfig
is <enabled>true</enabled>
. This should be pretty straight forward, it's a Boolean to enable/disable the switcher functionality we just implemented.
And we're done. So using the example above what you should see is field field2Depend1
displayed if you choose an option with value 2
on field1
, and field3Depend1
displayed if you choose an option with value 3
.
I have tested this example using only hide
and show
on a required field and it does appear to take visibility into account for validation. In other words, if field2Depend1
is required it will only be required when visible. No need for further configuration for that to work.
Hope this provides some help for anyone looking for a more out-of-the-box solution.