CHtml:activeRadioButtonList() htmloptions 'id' field is overwritten

When rendering an activeRadioButtonList like so




<?php echo CHtml::label($model->getAttributeLabel('effect'), 'itemGroup-Condition_effect'); ?>

<?php echo $form->radioButtonList($model, 'effect', Condition::$effects, array('id' => 'itemGroup-Condition_effect', 'class' => 'sharedInput', 'separator' => ' ', 'uncheckValue' => null)); ?>



The output looks like this




<div id="itemGroup-effect" class="row conditionHolder">

<label for="itemGroup-Condition_effect">Effect</label>           

<span id="Condition_effect">

     <input id="Condition_effect_0" class="sharedInput" value="boost" type="radio" name="Condition[effect]" /> 

     <label for="Condition_effect_0">Boost</label> 

     <input id="Condition_effect_1" class="sharedInput" value="blacklist" checked="checked" type="radio" name="Condition[effect]" /> 

     <label for="Condition_effect_1">Blacklist</label> 

     <input id="Condition_effect_2" class="sharedInput" value="defaults" type="radio" name="Condition[effect]" /> 

     <label for="Condition_effect_2">Default</label> 

     <input id="Condition_effect_3" class="sharedInput" value="overrides" type="radio" name="Condition[effect]" /> 

     <label for="Condition_effect_3">Whitelist</label>

</span>                

</div>



It seems like the ‘id’ field specified in the htmloptions of the activeradiobuttonlist is overwritten. Is there any way to specify your own id or prepend an id prefix to the span and radio button input fields?

My use case is I am rendering the same model fields more than once in the same form and showing/hiding them using jquery based on other selections in the form. The existing model field values won’t show as checked because there are duplicate ids on the page

Thanks

I ended up just extending the CHtml class like this and putting it in the components directory




class MyHtml extends CHtml {


    public static function activeRadioButtonList($model, $attribute, $data, $htmlOptions = array()) {

        self::resolveNameID($model, $attribute, $htmlOptions);

        $selection = self::resolveValue($model, $attribute);

        if ($model->hasErrors($attribute))

            self::addErrorCss($htmlOptions);

        $name = $htmlOptions['name'];

        unset($htmlOptions['name']);


        if (array_key_exists('uncheckValue', $htmlOptions)) {

            $uncheck = $htmlOptions['uncheckValue'];

            unset($htmlOptions['uncheckValue']);

        }

        else

            $uncheck = '';


        $hiddenOptions = isset($htmlOptions['id']) ? array('id' => self::ID_PREFIX . $htmlOptions['id']) : array('id' => false);

        $hidden = $uncheck !== null ? self::hiddenField($name, $uncheck, $hiddenOptions) : '';


        return $hidden . self::radioButtonList($name, $selection, $data, $htmlOptions);

    }


    /*

     * This method is overriden to allow for 

     * adding a prefix to the ids generated for inputs

     */


    public static function radioButtonList($name, $select, $data, $htmlOptions = array()) {

        $template = isset($htmlOptions['template']) ? $htmlOptions['template'] : '{input} {label}';

        $separator = isset($htmlOptions['separator']) ? $htmlOptions['separator'] : "<br/>\n";

        unset($htmlOptions['template'], $htmlOptions['separator']);


        $labelOptions = isset($htmlOptions['labelOptions']) ? $htmlOptions['labelOptions'] : array();

        unset($htmlOptions['labelOptions']);


        $items = array();

        $baseID = self::getIdByName($name);

        // customization to allow for idprefix

        $baseID = isset($htmlOptions['idprefix']) ? $htmlOptions['idprefix'] . $baseID : $baseID;

        unset($htmlOptions['idprefix']);

        $id = 0;

        foreach ($data as $value => $label) {

            $checked = !strcmp($value, $select);

            $htmlOptions['value'] = $value;

            $htmlOptions['id'] = $baseID . '_' . $id++;

            $option = self::radioButton($name, $checked, $htmlOptions);

            $label = self::label($label, $htmlOptions['id'], $labelOptions);

            $items[] = strtr($template, array('{input}' => $option, '{label}' => $label));

        }

        return self::tag('span', array('id' => $baseID), implode($separator, $items));

    }


}



And then just called the extended class


<?php echo MyHtml::activeRadioButtonList($model, 'effect', Condition::$effects, array('idprefix' => 'itemGroup-', 'class' => 'sharedInput', 'separator' => ' ', 'uncheckValue' => null)); ?>

This is now working fine for me. It’s not great having to copy two base methods from CHtml to this extended class but this is the best I could come up with for now. If anyone has any cleaner ideas that would be appreciated

Please explain a bit more why you need to render the same attribute input more then once?

I have a very dependent form. I have radio group A at the top of the form with a jquery click listener attached to it. When you click one of those options, radio group B appears below. The click listener function for radio group B needs to be different depending on what selection of A was made. So it is ok for the model to have to different fields that are null depending on what path you take entering the form fields.

So I see two ways to handle this. One is to have the radio group B multiple times on the page, attach click listeners to the different instances on document ready, and show/hide each one depending on radio group A selection. The other way, which I am leaning towards doing now after going through this, is to unbind then bind a different click listener for radio group B each time a radio group A option is selected