Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I was creating a CActiveForm with the ClientValidation enabled, but stepped in an error when I wrapped a RadioButtonList inside a UL container.

Whenever I submited the form I get a "field cannot be empty" message, even if the radios were checked.

My form:

$form=$this->beginWidget('CActiveForm', array(
 'id'=>'enrollment-form',
 'enableClientValidation'=>true,

 'clientOptions'=>array(
     'inputContainer'=>'ul',
     'validateOnSubmit'=>true,
 ),
));

And one of the RadioButtonLists I use:

<div id="drinks">
  <?php echo $form->label($model,'drink_id',array('class' => 'title')); ?>                
  <?php echo $form->radioButtonList($model,'drink_id', CHtml::listData($drinks, 'id', 'name'), array('container'=>'ul', 'template' => '<li class="radio_row">{input}{label}</li>','separator' => '')); ?>                
  <?php echo $form->error($model,'drink_id'); ?>
</div>

Was I making something wrong?

I studied the code of the jquery.yiiactiveform.js and found that my problem was that in the function that gets the value of the inputs, the value was not taken correctly, because the ID used to identify the inputs was not set in a span, or in the checkboxes/radios themselves (the id was set in the UL container I defined):

var getAFValue = function (o) {
    var type,
        c = [];
    if (!o.length) {
        return undefined;
    }
    if (o[0].tagName.toLowerCase() === 'span') {
        o.find(':checked').each(function () {
            c.push(this.value);
        });
        return c.join(',');
    }
    type = o.attr('type');
    if (type === 'checkbox' || type === 'radio') {
        return o.filter(':checked').val();
    } else {
        return o.val();
    }
};

So I solved this adding || o[0].tagName.toLowerCase() === 'ul':

var getAFValue = function (o) {
    var type,
        c = [];
    if (!o.length) {
        return undefined;
    }
    if (o[0].tagName.toLowerCase() === 'span' || o[0].tagName.toLowerCase() === 'ul') {
        o.find(':checked').each(function () {
            c.push(this.value);
        });
        return c.join(',');
    }
    type = o.attr('type');
    if (type === 'checkbox' || type === 'radio') {
        return o.filter(':checked').val();
    } else {
        return o.val();
    }
};

Maybe I was just making some mistake and this solution is just a crappy workaround... but maybe this is just a bug ¿?

The HTML generated:

<form id="enrollment-form" action="/enrollment" method="post">
  <div style="display:none"><input type="hidden" value="b06e1d1d796f838f30ba130f8d990034aa9fdad6" name="YII_CSRF_TOKEN" /></div>    
  <div id="enrollment-form_es_" class="errorSummary" style="display:none"><p>Please fix the following input errors:</p>
    <ul><li>dummy</li></ul>
  </div>

  <div id="drinks">
    <label class="title" for="EnrollmentForm_drink_id">Drinks</label>                
    <input id="ytEnrollmentForm_drink_id" type="hidden" value="" name="EnrollmentForm[drink_id]" />

    <ul id="EnrollmentForm_drink_id">
      <li class="radio_row">
        <input id="EnrollmentForm_drink_id_0" value="2" type="radio" name="EnrollmentForm[drink_id]" />
        <label for="EnrollmentForm_drink_id_0">Tea</label>
      </li>
      <li class="radio_row">
        <input id="EnrollmentForm_drink_id_1" value="1" type="radio" name="EnrollmentForm[drink_id]" />
        <label for="EnrollmentForm_drink_id_1">Juice</label>
      </li>
    </ul>                
    <div class="errorMessage" id="EnrollmentForm_drink_id_em_" style="display:none"></div>
  </div>

I noticed that if I didn't use any container when generating the RadioButtonList, Yii aplies a "class=success" to a span. And with my UL container, that class is not generated. When I've changed the Javascript, the class success is generated again.

** The HTML generated without the inputContainer option and without the last array in radioButtonList:

<div id="drinks">
  <label class="title" for="EnrollmentForm_drink_id">Bebidas</label>                
  <input id="ytEnrollmentForm_drink_id" type="hidden" value="" name="EnrollmentForm[drink_id]">

  <span id="EnrollmentForm_drink_id">
    <input id="EnrollmentForm_drink_id_0" value="2" type="radio" name="EnrollmentForm[drink_id]"> <label for="EnrollmentForm_drink_id_0">Tea</label><br>
    <input id="EnrollmentForm_drink_id_1" value="1" type="radio" name="EnrollmentForm[drink_id]"> <label for="EnrollmentForm_drink_id_1">Juice</label>
  </span>                
 <div class="errorMessage" id="EnrollmentForm_drink_id_em_" style="display:none"></div>            
</div>

As you can see, Yii generates a strange span that controls if the form is valid or not, by aplying to it the class "success". If I use the inputContainer UL then this class="success" is not generated (with my workaround it is generated and it works).

share|improve this question
What does the generated html look like? – jmarkmurphy Jul 25 at 16:50
Added the HTML generated and some other explanation. – Fer Nando Jul 26 at 8:12
What does the HTML look like when you remove inputContainer from clientOptions, and the last array from radioButtonList? – jmarkmurphy Jul 26 at 16:23
Added the HTML. The main problem is that with the inputContainer, Yii does not aply class="success" to the <ul>. – Fer Nando Jul 29 at 9:13

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.