jquery.yiiactiveform.js not included when form is rendered through ajax

I want to use client validation on an activeform but in some cases it is not working. I see no error messages in the consoles, but I noticed that jquery.yiiactiveform.js is not being included.

Undoubtedly the problem is related to the somewhat convoluted way the page is being rendered. The form is not shown initially - the user first has to make a choice from a drop-down list. That triggers an ajax request, and the response is a renderPartial of a view which contains the activeForm. I used this approach because the structure of the form will be different according to options they select, and this was the most straightforward way to code it under the time pressure I faced. My current plan is to forget about ajax and just make separate views, but that will take some effort.

Minimal code example. The initial view, with a drop-down list:




<?php

$list = array(0 => 'a', 1 => 'b');

echo CHtml::dropDownList('group_id', '', $list, array('ajax' => array(

        'type' => 'POST',

        'url' => $this->createUrl('group/formAjax2'),

        'dataType' => 'json',

        'success' => "js:function(data){ 

                            document.getElementById('formContent').innerHTML=data.form;                            

                         }"

        )));

?>

<div id="formContent">

</div>



The idea is that the user makes a choice from the drop-down, and the form gets inserted into the formContent div. Here is the controller action (formAjax2) that services the Ajax request:




 public function actionFormAjax2() {

        $model= new Group();

        $result['form'] = $this->renderPartial('_form2', array('model' => $model), true);

        echo CJSON::encode($result);

    }



And here is ‘_form2’ which is inserted into the view’s formContent div:




<div class="form">

    <?php   

    $form = $this->beginWidget('CActiveForm', array(

        'id' => 'group-form',

        'enableAjaxValidation' => false,

        'enableClientValidation' => true,

        'action' => 'myAction',

            ));

    ?>

    <?php echo $form->errorSummary($model); ?>

    <div class="row">

        <?php echo $form->labelEx($model, 'name'); ?>

        <?php echo $form->textField($model, 'name', array('size' => 60, 'maxlength' => 128)); ?>

        <?php echo $form->error($model, 'name'); ?>

    </div>

    <div class="row buttons">

        <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>

    </div>

    <?php $this->endWidget(); ?>

</div>



When I run this code, it works correctly, in that changing the drop-down causes the form to be loaded, but client validation is not happening in the form, and jquery.yiiactiveform.js is not loaded.

Now, if I forget about using ajax and just render the form directly, like this:




public function actionCreateLocal4($option_id=NULL) {

         $model= new Group();

         $this->render('_form2', array('model'=>$model));        

    }



then client validation is working fine. So obviously by passing the form through ajax I am breaking something. Any advice?

Quick fix: set the fourth parameter of renderPartial() to true.

Then search the forum for side effects you will encounter if repeating the renderPartial().

(Use google “site:yiiframework.com” if forum search doesn’t return anything.)

/Tommy

Unfortunately the quick fix did not solve it. To be clear I altered the line to read as follows:




$result['form'] = $this->renderPartial('_form2', array('model' => $model), true, true);



I can see that the ajax response is including javascript code now where it wasn’t before, also includes <script> tags that point to jquery.yiiactiveform.js and jquery.js, but still no client validation happening.

I wondered if those script lines were doing anything – I didn’t see any sign that yiiactiveform.js was being loaded when the ajax response happened, no network transfer or anything – so I added this line before the renderPartial above:




Yii::app()->clientScript->scriptMap=array('jquery.yiiactiveform.js'=>false,'jquery.js'=>false,);



and created another activeForm on the first view (next to the drop-down), so that the form rendered via ajax is the second one. In this case yiiactiveform.js and jquery.js are already loaded when the first form renders, and client validation on the first form works fine. The second form when passed through ajax renders fine as usual, and the code does not include the <script> includes, but does include the client validation javascript. Yet still, nothing happens, no client validation. No console errors or anything.

I’m a bit out of my depth here and don’t fully understand what’s going on as to how these javascript functions are bound to the activeforms. If there is a simple workaround that would be nice; else I’ll abandon these efforts and re-architect these pages when I find the time. Thanks.

Fixed it. It was related to the way I was processing the ajax request, wrapping the result of the render inside a JSON array somehow broke the javascript. So the lesson is, don’t do that! :)

Updated view, note the change to the ajax code, using update instead of changing the HTML of the div:




<?php

$list = array(0 => 'a', 1 => 'b');

echo CHtml::dropDownList('group_id', '', $list, array('ajax' => array(

        'type' => 'POST',

        'url' => $this->createUrl('group/formAjax2'),       

        'update' => "#formContent"

        )));

?>


<div id="formContent">

</div>



And controller, note using $this->renderPartial instead of echoing via JSON, and note 3rd param is false and 4th true:




 public function actionFormAjax2() {

        $model= new Group();

        $this->renderPartial('_form2', array('model' => $model), false, true);        

    }



Now I can indeed see network transfers of jquery.js and jquery.yiiactiveform.js accompanying the ajax response. Of course this is the second time jquery.js is loaded so I still may need to adjust this with that scriptMap code. But seems to be working fine now.