0

For a component I have a field item_type that needs to be saved in its own database column for ease of searching, filtering etc, and a set of configurations which have global option defaults so are stored as parameters in the database params column for the component eg item_colour item_size etc. So the item_type field in the form xml appears in the main fieldset and the parameters fields appear in the params fieldset.

I want to use showon field attributes in the form to determine which fields will show depending on the setting of item type. In the edit view I want to render the fields all on the same tab rather than use a separate tab for params.

My problem is that showon only seems to work with fields in the same fieldset. Is there any syntax that will get showon to work with a field in a different fieldset.

So the form xml looks like this

<form>
    <fieldset name="default">
        <field name="item_type" type="list"
            label="Select type" description=""
        >
            <option value="0">Basic</option>
            <option value="1">Simple</option>
            <option value="2">Complex</option>
        </field>
    </fieldset>
    <fields name="params">
        <fieldset name="params" label="JGLOBAL_FIELDSET_DISPLAY_OPTIONS" >
            <field name="item_colour" type="color"
            label="Colour" description=""
            default="#0000ff" format="hex"
            showon="item_type:1"
            />
            <field name="item_icon" type="text"
            label="Icon" description=""
            default=""
            showon="item_type:2"
            />
        </fieldset>
    </fields>
</form>

and the edit.php includes this

<?php echo $this->form->renderField('item_type'); ?> 
<?php echo $this->form->renderField('item_colour','params'); ?> 
<?php echo $this->form->renderField('item_icon','params'); ?> 

The problem is that the showon conditions do not work. If I move the item type field into the params fieldset and change it to <?php echo $this->form->renderField('item_type','params'); ?> then it works, but of course the item_type gets saved as a parameter, not in its own column.

2 Answers 2

2

showon indeed works only within the same fieldset.

The javascript related with the showon, can handle fields from different groups/fieldsets. The problem resides in the php logic of the FormField class. What i did to resolve that issue, was to create my own field (extending FormField), where i have overwritten the public function renderField

This is the function that handles what will be passed in the data-showon attribute of a field, which is then handled by the page's javascript.

My code looks like that:

 public function renderField($options = [])
    {
        if ($this->hidden) {
            return $this->getInput();
        }

        if (!isset($options['class'])) {
            $options['class'] = '';
        }

        $options['rel'] = '';

        if (empty($options['hiddenLabel'])) {
            if ($this->getAttribute('hiddenLabel')) {
                $options['hiddenLabel'] = $this->getAttribute('hiddenLabel') == 'true';
            } else {
                $options['hiddenLabel'] = $this->hiddenLabel;
            }
        }

        if (empty($options['hiddenDescription'])) {
            if ($this->getAttribute('hiddenDescription')) {
                $options['hiddenDescription'] = $this->getAttribute('hiddenDescription') == 'true';
            } else {
                $options['hiddenDescription'] = $this->hiddenDescription;
            }
        }
        /*
         * Show on that works globally across the form
         */
        if ($this->showon) {
            $showonParts = explode('.', $this->showon);
            $group = $this->group;
            $showon = $this->showon;
            if (count($showonParts) > 1) {
                $showon = array_pop($showonParts);
                $group = implode('.', $showonParts);
            }

            $options['rel'] = ' data-showon=\'' .
                json_encode(FormHelper::parseShowOnConditions($showon, $this->formControl, $group)) . '\'';
            $options['showonEnabled'] = true;
        }
        $data = [
            'input' => $this->getInput(),
            'label' => $this->getLabel(),
            'options' => $options,
        ];

        $data = array_merge($this->getLayoutData(), $data);

        return $this->getRenderer($this->renderLayout)->render($data);
    }

To utilize the above you will have:

  1. Use that type of field in your xmls (using the type attribute). Of course to do that you should have prefixed the folder where you store you fields.
  2. The syntax is fieldsId.fieldId + condition + value Do note: I mention fieldsId NOT fieldsetId. i.e.
<fields name="attribs">
    <fieldset name="basic-attribs" label="COM_JFILTERS_BASIC_ATTRIBS_FIELDSET_LABEL">
        <!-- Store the type of the dynamic filter. We use that in order not to query the db. Fed during the filters generation -->
        <field
                name="myFieldName"
                type="myField"
                value=""
        />
   </fieldset>
</fields>

Should be accessed as: showon="attribs.myFieldName!:10" Will show your field for any value other than 10

Do note: I have tested that in J4 only. Hopefully will work in J3 as well, and if not, minor changes are required.

1
  • Neat. I like that approach - much better than trying to disentangle it on form save, or wherever, by copying the item_type value to the required db column and removing it from params then putting it back in getItem(). I'm sticking with J3 for the foreseeable future so I won't mark it as accepted until I've tried it. Many thanks for speedy good response.
    – RogerCO
    Commented Sep 2, 2021 at 11:10
0

I liked @sakis answer, but then I realised that in the full case I would have to write custom field types of text, textarea, color, list, and radio form field types. This seemed like a lot of work so I wondered if I could do something in javascript with the onchange event of the item_type field.

This solution also seems to work without having to include any custom fields:

  1. put item_type field in the main (default) fieldset so that on form save the value gets written to the database field.
  2. add a new hidden field hidden_item_type in params fields/fieldset and set the showon events of the subsidiary params fields to depend on 'hidden_item_type` Be sure to render this hidden field on the form in the edit view.
  3. put javascript onchange="..." on the visible item type which sets the value of the hidden field to the new value of the visible one and dispatches the hidden field's onchange event.

Thus in the form xml:

<!-- in the main fieldset -->
    <field name="item_type" type="list"
    label="Item Type" description=""
    onchange="var targ=document.getElementById('jform_params_hidden_item_type'); 
targ.value=value; targ.dispatchEvent(new Event('change'));"
        >
            <option value="0">Default</option>
            <option value="1">Simple</option>
            <option value="2">Complex</option>
        </field>
        
</fieldset> 
<fields name="params">
    <fieldset name="params" label="JGLOBAL_FIELDSET_DISPLAY_OPTIONS" >
        <field name="hidden_marker_type" type="hidden"
            default=""
        >
        <field name="marker_colour" type="color" 
            label="Colour" description="" 
            default="#0000FF" format="hex"
            showon="hidden_item_type:2"
        />  
<!-- other fields as required and close fieldset and fields -->

this seems to work ok and to my mind is simple. There may be ways of improving it (eg make the onchange a separate function which could be called by different fields passing the relevant target id).

Thanks to Sakis for making me think about the fact that Joomla must be using javascript to do the showon function. (PS I can't work out how to tag someone here, @xxx doesn't seem to work in preview and simply putting their profile link won't notify them?) (PPS I'm sticking with J3 for the foreseeable future as converting custom stuff to J4 seems to be a right royal pain and the new admin interface is horrid I think - J4 is a turkey as far as I'm concerned)

1
  • (Pinging only works via comments and there are qualifying factors as to who can be pinged based on the type of contributions that they've made on the page.) Commented Sep 7, 2021 at 10:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.