5

I have a Yii form which calls a render partial from another model (team has_many team_members). I want to call via ajax a partial view to add members in team/_form. All works (call, show, save) except for ajax validations (server and client side). If i submit form, member's model isn't validating, even in client side, it's not validating the required fields.

Any clue?

//_form

<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'team-form',
        'enableAjaxValidation'=>true,
        'enableClientValidation'=>true,
        'clientOptions'=>array(
            'validateOnSubmit'=>true,
            'validateOnChange'=>true

        ),
        'htmlOptions' => array('enctype' => 'multipart/form-data'),
)); ?>

//Controller

public function actionMember($index)
{
    $model = new TeamMember();
        $this->renderPartial('_member',array(
            'model'=> $model, 'index'=> $index
        )
                ,false,true
                ); 
}  

public function actionCreate()
{
        $model=new Team;
        $members = array();
        if(isset($_POST['Team']))
        {
                $model->attributes=$_POST['Team'];

                if(!empty($_POST['TeamMember'])){
                foreach($_POST['TeamMember'] as $team_member)
                            {
                                $mem = new TeamMember();
                                $mem->setAttribute($team_member);
                                if($mem->validate(array('name'))) $members[]=$mem;
                            }
                }
                        $this->redirect(array('team/create','id'=>$model->id,'#'=>'submit-message'));

        }

        $members[]=new TeamMember;
        $this->performAjaxMemberValidation($members);
        $this->render('create',array(
                'model'=>$model,'members'=>$members
        ));

}

//_member

<div class="row-member<?php echo $index; ?>">
    <h3>Member <?php echo $index+1; ?></h3>
    <div class="row">
    <?php echo CHtml::activeLabel($model, "[$index]name",array('class'=>'member')); ?>
    <?php echo CHtml::activeTextField($model, "[$index]name",array('class'=>'member')); ?>
    <?php echo CHtml::error($model, "[$index]name");?>    
    </div>
</div>

ProcessOutput was set to true. No dice. Switch renderPartial() to render(). No dice.

groovekiller
  • 1,122
  • 2
  • 8
  • 20
  • MEM, coppettim : are you the same guy ? If not, why did you edit this question and add the last line, how could you know this ?? – soju Apr 23 '13 at 17:42
  • @soju: We are not the same guy. But we both are working on this same issue. - And neither of us was able to find the answer yet. – MEM Apr 23 '13 at 18:00
  • What are your rules() ? – JorgeeFG Apr 23 '13 at 18:46
  • @Jorge the rules are on `TeamMember` Model above. That is part of the method rules(). – MEM Apr 23 '13 at 19:25

3 Answers3

6

If you will look at the CActiveForm::run:

$cs->registerCoreScript('yiiactiveform');
//...
$cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiactiveform($options);");

Then you will understand that you validation will not work, because you render partial and not the whole page. And these scripts show up at the bottom of the page. So you should solve this by execute these scripts.

After you partial is rendered, try to get activeform script which should be stored at the scipts array:

$this->renderPartial('_member',array('model'=> $model, 'index'=> $index));
$script = Yii::app()->clientScript->scripts[CClientScript::POS_READY]['CActiveForm#team-form'];

after, send it with rendered html to page:

echo "<script type='text/javascript'>$script</script>"

Also remember before you will append recieved html on the page you should include jquery.yiiactiveform.js, if you not already did it(by render another form, or registerCoreScript('yiiactiveform')), on the page from calling ajax request. Otherwise javascript error will raised.

Hope this will help.

Edit: Sorry I'm not understood that you are render part of form and not the whole. But you validation will not work exactly with the same issue. Because jQuery('#$id').yiiactiveform($options); script was not created for the field.

ole
  • 5,166
  • 5
  • 29
  • 57
  • Sorry, didnt understood where to put "$script = Yii::app()->clientScript->scripts[CClientScript::POS_READY]['CActiveForm#team-form'];".. I call my renderPartial in controller, so $script will not be visible in _member view. – groovekiller Apr 24 '13 at 09:36
1

The actual problem is that the ActiveForm saves its attributes to be validated in the "settings" data attribute. I see you are already using indexes so what you need to add the new elements to this settings object in order for the validation to work. After the ajax response this is what must be done:

//Get the settings object from the form
var settings = $("#form").data('settings');
//Get all the newly inserted elements via jquery
$("[name^='YourModel']", data).each(function(k, v) {
    //base attribute skeleton
    var base = {
        model : 'YourModel',
        enableAjaxValidation : true,
        errorCssClass : 'error',
        status : 1,
        hideErrorMessage : false,
    };

    var newRow = $.extend({
        id : $(v).attr('id'),
        inputID : $(v).attr('id'),
        errorID : $(v).attr('id') + '_em_',
        name : $(v).attr('name'),
     }, base);
     //push it to the settings.attribute object
     settings.attributes.push(newRow);
 });
 //update the form
 $("#form").data('settings', settings);

```

This way the ActiveForm will be aware of the new fields and will validate them.

Nikola
  • 493
  • 4
  • 12
  • Nice work! This helps to solve the problem. Try the whole day to solve this issue. With your solution the fix was made in minutes. Thanks for sharing – funktioneer Apr 14 '14 at 14:59
0

Well, setting processOutput to true in renderPartial (in order to make client validation works on newly added fields) will not help in this case since it will only work for CActiveForm form and you don't have any form in your _member view (only input fields).

A simple way to deal with this kind of problem could be to use only ajax validation, and use CActiveForm::validateTabular() in your controller to validate your team members.

soju
  • 25,111
  • 3
  • 68
  • 70
  • I did it, and _member loads with fields validated. But them not change their status when i enter data inside inputs, keep saying "this field is mandatory" and so on.. – groovekiller Apr 24 '13 at 09:37
  • Did you set `enableAjaxValidation` to true and `enableClientValidation` to false ? – soju Apr 24 '13 at 09:41
  • Do you use `validateTabular` ? Add corresponding code to your question – soju Apr 24 '13 at 09:49
  • public function actionMember($index){ $model = new TeamMember(); if (Yii::app()->request->isAjaxRequest) { CActiveForm::validateTabular( array( $model)); $this->renderPartial('_member',array( 'model'=> $model, 'index'=> $index ) ,false,true ); } } – groovekiller Apr 24 '13 at 09:52
  • Please do not add code like this in your comment, update your question instead... You should use validateTabular in your main action (the one that handles your team form), not in member action... – soju Apr 24 '13 at 09:57