2

I need to be able to add styling class to form fields parent wrappers when using the xml attribute method, with a new attribute cgClass (as in control-group) to achieve <div class="control-group myclass">

<field name="name" type="text" cgClass="myclass" />

The current method adds a class attrib to the field element using the xml attribute class, but that is useless for styling the parent container and children.

The desired output should be

 <div class="control-group myclass">
   <div class="control-label">
    <label id="jform_params" for="jform_params">Label</label>
   </div>
   <div class="controls">
    <input type="text" name="jform[params]" id="jform_params" value="">
   </div>
 </div>

The goal is to be able to group fields into columns

This screen capture shows 2 columns visual of fields arrangement desired

I need to do this without using a layout override.

I can achieve the desired output when I edit \libraries\src\Form\FormField.php within the renderField() method and add the following condition, however that's not appropriate since it is overwritten on updates.

public function renderField($options = array())
{
  // added condition
  if( $this->getAttribute('cgClass') ) {
    $options['class'] = $this->getAttribute('cgClass');
  }
}

How can this be done?


Additional Information

The core layout file layouts/joomla/form/renderfield.php is constructed to do the task as desired.

<?php defined('JPATH_BASE') or die;

extract($displayData);

if (!empty($options['showonEnabled']))
{
  JHtml::_('jquery.framework');
  JHtml::_('script', 'jui/cms.js', array('version' => 'auto', 'relative' => true));
}

$class = empty($options['class']) ? '' : ' ' . $options['class'];
$rel   = empty($options['rel']) ? '' : ' ' . $options['rel'];
?>
<div class="control-group<?php echo $class; ?>"<?php echo $rel; ?>>
  <?php if (empty($options['hiddenLabel'])) : ?>
    <div class="control-label"><?php echo $label; ?></div>
  <?php endif; ?>
   <div class="controls"><?php echo $input; ?></div>
</div>

However the renderField() method in libraries/src/FormFormField.php does not send a value to the $options['class'] variable. As if someone forgot to complete the condition.

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

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

    $options['rel'] = '';

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

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

    $data = array(
        'input'   => $this->getInput(),
        'label'   => $this->getLabel(),
        'options' => $options,
    );

    return $this->getRenderer($this->renderLayout)->render($data);
}
6
  • OK, I'll bite. Why do you need to do it without a layout override? The override mechanism is put into Joomla specifically to achieve that goal, I'm curious why you don't want to use it?
    – Arlen
    Jan 21, 2020 at 15:21
  • @Arlen the function will be used in a distributed extension and a user may already have the override in use. The construction of the layout file in layouts/joomla/form/renderfield.php is written to do what I need, however the afore mentioned renderField() method does not comply. The variable is left empty
    – Nadal
    Jan 21, 2020 at 20:51
  • Can you not just pass the options in when you call the Form renderField in your view layout file? I don't understand why it has to be in the XML form definition. Jan 22, 2020 at 13:32
  • @Nadal Thank you for satisfying my curiosity. I think that means you're creating your own component/module and want to do this in it. But if the intended user already has an override in place, there's a good probability that it will override what you're doing, as well, won't it?
    – Arlen
    Jan 22, 2020 at 19:02
  • @Arlen yes if the user's override is altering that specific variable, it will not use what I'm doing, though such an override is most likely done by developers since it pertains to form fields display during any content editing. In such a case, the display will simply revert to the original format and not break. I currently achieve the desired goal using jQuery methods closest() and addClass() to find elements and add the class, but it is inconsistent in some instances.
    – Nadal
    Jan 22, 2020 at 19:41

1 Answer 1

2

Solution used

I created a form element extension of JFormField class and used the renderField() method to execute the process of wrapping div elements around groups of field elements.


UPDATE

I added getInput() method to the field element extension due to missing field value errors thrown when used in com_config option view.

Also added the language constant interpreter to elements which output text eg: JText::_($element['text']).

The coding has been updated to show the changes.


<?php defined('JPATH_PLATFORM') or die;
/* 
* render unwrapped open div element 
*/

class JFormFieldCmsegroup extends JFormField
{
    protected $type = 'cmsegroup';
    protected function getInput() {}

    public function renderField($options = [])
    {
        $element    = $this->element;
        $fieldtype  = $element['fieldtype'];
        $class      = ' class="'.$this->class.'"';
        $title      = $handle_slideclass= $content_slideclass='';
        $text       = (isset($element['text']) ? '<div class="textbox">'.JText::_($element['text']).'</div>':'');
        $icon       = (isset($element['icon']) ? '<span class="icon"><i class="'.$element['icon'].'"></i></span>':'');


        if( !empty($element['title']) ) 
        {
            if( isset($element['slider']) ) 
            {
                list($handle, $content) = explode(',', $element['slider']);
                $handle_slideclass = ' slide-tab '.$handle;
                $content_slideclass = ' '.$content;
            }

            $title = '<h3 class="'.$handle_slideclass.'">'.$icon.'<span>'.JText::_($element['title']).'</span></h3>';
        }

        $head = (isset($element['head']) ? '
        <div'.$class.'>
        '.$title.'
        <div class="cmse-group'.$content_slideclass.'">
        '.$text.'
        <div class="cmse-inner">' : 
        '');
        $foot = (isset($element['foot']) ? '</div></div></div>' : '');

        return $head.$foot;
    }
}

Use in manifest XML

Only the type, head and foot attributes are required.

The slider attribute creates two class definitions which are inserted in order to the H3 element and the div below it. This should allow use with any drop slide javascript function. Otherwise the renderField() coding can be modified as needed.

<field type="cmsegroup" head="true" />

Fields

<field type="cmsegroup" foot="true" />

<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="module" client="site" method="upgrade">
    <name>A Module</name>
    <creationDate></creationDate>
    <author></author>
    <copyright></copyright>
    <license></license>
    <authorEmail></authorEmail>
    <authorUrl></authorUrl>
    <version>1.0</version>
    <description>test module</description>

    <files>
        <filename module="mod_cmse_dev">mod_cmse_dev.php</filename>
        <filename>index.html</filename>
    </files>

<config>
    <fields name="params" addfieldpath="libraries/cmselib/elements">
        <fieldset name="basic">

<!-- Add opening DIV along with H3 -->
            <field 
            type="cmsegroup" 
            head="true" 
            slider="ahandle,acontent" 
            class="my-parent-wrapperclass otherclass" 
            title="Output in H3 element" 
            icon="fas fa-cogs" 
            text="Output in a div element at the top of the group" 
            />

<!-- Fields -->
            <field type="text" name="element" label="The Label" />
            <field type="radio" name="rsds" class="btn-group btn-group-yesno" default="0" label="Radio">
                <option value="1">JYES</option>
                <option value="0">JNO</option>
            </field>

<!-- Closing DIV -->
            <field type="cmsegroup" foot="true" />


        </fieldset>
    </fields>
</config>
</extension>

Result HTML output

    <div class="cmse-group slide-group">
    <h3 class="slide-tab ahandle isdown">
    <span class="icon"><i class=""></i></span>
    <span>The Group Title</span>
    </h3>

    <div class="cmse-group acontent">
        <div class="textbox">The text inserted here</div>
        <div class="cmse-inner">

            <!-- Default fields -->
            <div class="control-group">
                <div class="control-label">
                    <label id="jform_params_wshf-lbl" for="jform_params_wshf">Jump</label>
                </div>
                <div class="controls">
                    <input type="text" name="jform[params][wshf]" id="jform_params_wshf" value="">
                </div>
            </div>

            <div class="control-group">
                <div class="control-label">
                    <label id="jform_params_rsds-lbl" for="jform_params_rsds">Radio</label>
                </div>
                <div class="controls">
                    <fieldset id="jform_params_rsds" class="btn-group btn-group-yesno radio">
                    <input type="radio" id="jform_params_rsds0" name="jform[params][rsds]" value="1">
                    <label for="jform_params_rsds0" class="btn">Yes</label>

                    <input type="radio" id="jform_params_rsds1" name="jform[params][rsds]" value="0" checked="checked">
                    <label for="jform_params_rsds1" class="btn active btn-danger">No</label>
                    </fieldset>
                </div>
            </div>
            <!-- default fields end -->

        </div>
    </div>
</div>

Output

result HTML

Your Answer

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

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