5

In http://alanstorm.com/magento_system_configuration_in_depth_tutorial @AlanStorm gives a very good tutorial for system configuration.

He also explains how to use a <depends> tag to make a field show only when a specific value is set in another field.

My Q is how can I make fieldB visible if field A has either value V1 or V2. and are there any other options with the <depends> ?

Also If someone knows where in magento's code this is implemented I would also like to have a look at the code myself.

Thanks

epeleg
  • 10,347
  • 17
  • 101
  • 151

4 Answers4

15

If I correctly understand release notes from Magento 1.7.0.1, this functionnality has been implemented (http://goo.gl/ZgHG0). I have succeddfully tested it on a Magento CE 1.7.0.2.

You must declare a separator parameter in the field dependancy like this :

<depends>
    <depends_from_field separator=",">
        depends_from_field_value_1,depends_from_field_value_2
    </depends_from_field>
</depends>

Note that depends_from_field_value_1 and depends_from_field_value_2 are separated by a comma, the exact symbol that is declared in separator=","

Hervé Guétin
  • 4,392
  • 4
  • 29
  • 36
3

I'm not sure where in Alan's article it's explained, but there is how I do it: it's just a bit of javascript.
In your group you put a comment tag with the javascript embedded into .
For example, here is my code that checks the value of one field in order to show (or not) another one:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <sections>
        <points_options translate="label" module="points">
            <tab>general</tab>
            <label>Loyalty Points</label>
            <frontend_type>text</frontend_type>
            <sort_order>1002</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <groups>
                <config_points translate="label">
                    <label>Configuration</label>
                    <comment><![CDATA[
                        <script type="text/javascript">
                            checkExpirationPeriod = function() {
                                if ($('points_options_config_points_expiration_period').getValue() > 0) {
                                    $('points_options_config_points_expiration_reminder').up(1).appear();
                                } else {
                                    $('points_options_config_points_expiration_reminder').up(1).fade();
                                }
                            }

                            Event.observe(window, 'load', function() {
                                Event.observe('points_options_config_points_expiration_period', 'change', checkExpirationPeriod);
                                checkExpirationPeriod();
                            })
                        </script>
                    ]]></comment>

as you can see, I write a small function which check one field's value to determine if show another one or not. I then link the onchange event to the function and trigger the function to show correct fields as the page is loaded.
For your needs, just add the condition in the js function.
Hope That Helps

OSdave
  • 8,538
  • 7
  • 45
  • 60
  • However, looks like I did not manage the escaping on my Q properly and the was invisible in both places. so I now fixed the Q, and I am hoping still that someone can provide assistance with utilizing the tag. Note that the "code in comment" trick makes it hard to translate comments (which can be a non issue if you put this code in the comment of a field that does not actually has a real comment). – epeleg Jan 31 '11 at 20:09
  • oddly enough, when commenting can be written just as is. while when posting the Q it has to be written <depends> or it will become invisible html. – epeleg Jan 31 '11 at 20:11
  • 1
    @epeleg, use backticks ` around tags to prevent the WYSIWYG interpreting them as HTML. – clockworkgeek Jan 31 '11 at 20:30
  • ok, now it makes more sense :) have you tried to put a second tag into ? – OSdave Feb 01 '11 at 10:09
  • I tried `v1,v2` and `v1v2`. If I could find where this is implemented in code maybe it could shed some light on the full syntax. – epeleg Feb 02 '11 at 15:09
3

There is a better way, but you will need to override the core files

Override the method under the following file app\code\core\Mage\Adminhtml\Block\Widget\Form\Element\Dependence.php

    public function addFieldDependence($fieldName, $fieldNameFrom, $refValues)
{
    /*
    if (is_array($refValues)) {
        Mage::throwException('Dependency from multiple values is not implemented yet. Please fix to your widget.xml');
    }
    */
    $this->_depends[$fieldName][$fieldNameFrom] = $refValues;
    return $this;
}

On the app\code\core\Mage\Adminhtml\Block\System\Config\Form.php Modify the method initFields

if ($e->depends) {
                foreach ($e->depends->children() as $dependent) {
                    $dependentId = $section->getName() . '_' . $group->getName() . '_' . $fieldPrefix . $dependent->getName();
                    if ($dependent->count()) {
                        $dependentValue = (array) $dependent;
                        $dependentValue = array_values($dependentValue);
                    } else {
                        $dependentValue = (string) $dependent;
                    }

                    $this->_getDependence()
                        ->addFieldMap($id, $id)
                        ->addFieldMap($dependentId, $dependentId)
                        ->addFieldDependence($id, $dependentId, $dependentValue);
                }
            }

Modify the javascript file js\mage\adminhtml\form.js

trackChange : function(e, idTo, valuesFrom)
{
    // define whether the target should show up
    var shouldShowUp = true;
    for (var idFrom in valuesFrom) {

        if (valuesFrom.hasOwnProperty(idFrom)) {
            if (typeof(valuesFrom[idFrom])=="object") {
                shouldShowUp = false;
                for(var idVal in valuesFrom[idFrom]) {
                    if (valuesFrom[idFrom].hasOwnProperty(idVal)) {
                        if (typeof(idVal)!="undefined" && ($(idFrom).value == valuesFrom[idFrom][idVal])) {
                            shouldShowUp = true;
                        }
                    }
                }
            } else if (typeof(valuesFrom[idFrom])=="string") {
                if ($(idFrom).value != valuesFrom[idFrom]) {
                    shouldShowUp = false;
                }
            }
        }
        /*
        if ($(idFrom).value != valuesFrom[idFrom]) {
            shouldShowUp = false;
        }
        */
    }

    // toggle target row
    if (shouldShowUp) {
        $(idTo).up(this._config.levels_up).select('input', 'select', 'td').each(function (item) {
            if (!item.type || item.type != 'hidden') { // don't touch hidden inputs, bc they may have custom logic
                item.disabled = false;
            }
        });
        $(idTo).up(this._config.levels_up).show();
    } else {
        $(idTo).up(this._config.levels_up).select('input', 'select', 'td').each(function (item){
            if (!item.type || item.type != 'hidden') { // don't touch hidden inputs, bc they may have custom logic
                item.disabled = true;
            }
        });
        $(idTo).up(this._config.levels_up).hide();
    }
}

Use the following syntax for multiple values dependency on your xml

                            <depends>
                            <field1>
                                <val1>text</val1>
                                <val2>radio</val2>
                            </field1>
                        </depends>
  • Thanks andrew. I have not verified this solution but it looks solid. If anyone actually tries this, please post a comment. – epeleg May 03 '11 at 20:16
  • I tried it, and it ALMOST worked. It's probably because I'm on 1.6.2.0 and this solution was meant for an earlier Magento version. Anyway, check my answer below, if you're interested. Now it works for me. Thank you, Andrew! – pancake Mar 08 '12 at 00:08
0

Andrew's answer almost did the trick. I'm on 1.6.2.0 right now and I modified the initFields() method in app\code\core\Mage\Adminhtml\Block\System\Config\Form.php as follows:

if ($e->depends) {
    foreach ($e->depends->children() as $dependent) {
        Mage::log((array)$dependent);
        $dependentId = $section->getName()
            . '_' . $group->getName()
            . '_' . $fieldPrefix
            . $dependent->getName();

        if ($dependent->hasChildren()) {
            $dependentValue = (array) $dependent;
            $dependentValue = array_values($dependentValue);
        } else {
            $dependentValue = (string) $dependent;
        }

        $shouldBeAddedDependence = true;
        $dependentFieldName      = $fieldPrefix . $dependent->getName();
        $dependentField          = $group->fields->$dependentFieldName;
        /*
         * If dependent field can't be shown in current scope and real dependent config value
         * is not equal to preferred one, then hide dependence fields by adding dependence
         * based on not shown field (not rendered field)
         */
        if (!$this->_canShowField($dependentField)) {
            $dependentFullPath = $section->getName()
                . '/' . $group->getName()
                . '/' . $fieldPrefix
                . $dependent->getName();
            if (is_array($dependentValue)) {
                foreach ($dependentValue as $dependentOption) {
                    $shouldBeAddedDependence |= $dependentOption != Mage::getStoreConfig(
                        $dependentFullPath,
                        $this->getStoreCode()
                    );
                }
            } else {
                $shouldBeAddedDependence = $dependentValue != Mage::getStoreConfig(
                    $dependentFullPath,
                    $this->getStoreCode()
                );
            }
        }
        if($shouldBeAddedDependence) {
            $this->_getDependence()
                ->addFieldMap($id, $id)
                ->addFieldMap($dependentId, $dependentId)
                ->addFieldDependence($id, $dependentId, $dependentValue);
        }
    }
}

Also it's not necessary to edit the core files. I overrode the admin theme to insert my own version of form.js and rewrote the two PHP classes using the config.xml of a custom module.

pancake
  • 1,923
  • 2
  • 21
  • 42