Executing JQuery script on form submit

I’ve built a form that contains a Multi Select Transfer using this example. The user can move items between the two dropdownfields $multiSelect1 and $multiSelect2.

The _form.php file:




<?php

Yii::app()->clientScript->registerScript('select-transfer', "

    $().ready(function() {

        $('#remove').click(function() {

            return !$('#".$model->getModelName()."_multiSelect1 option:selected').remove().appendTo('#".$model->getModelName()."_multiSelect2');

        });

        $('#add').click(function() {

            return !$('#".$model->getModelName()."_multiSelect2 option:selected').remove().appendTo('#".$model->getModelName()."_multiSelect1');

        });

       $('form').submit(function() {

            $('#".$model->getModelName()."_multiSelect1 option').each(function(i) {

                $(this).attr(\"selected\", \"selected\");

            });

        });

    });

");

?>


<div class="form wide">


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

    'id'=>'rule-form',

    'enableAjaxValidation'=>false,

)); ?>


    <p class="note">Fields with <span class="required">*</span> are required.</p>


   <div class="row">

        <?php if ($model->isNewRecord)

            {

                echo $form->labelEx($model,'type');

                echo $form->dropDownList($model,'type',$model->getTypeOptions(),array(

                    'empty'=>yii::t('core','Please select'),

                    'ajax' => array(

                        'type'=>'POST',

                        'url'=>CController::createUrl('/user/rule/ajaxparentselect'),

                        'update'=>'#Rule_multiSelect2',

                    ),

                ));

                echo $form->error($model,'type');

            }

            else

            {

                echo $form->label($model,'type');

                echo CHtml::encode($model->getTypeText());

            }

        ?>

    </div>


    <div id="multi-select-transfer" class="row multi-select-transfer">

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

        <div id="multiSelect1" class="multi-select-transfer">

            <p style="text-align:center"><b><?=yii::t('core','Selected'); ?>:</b><br />

            <?php

            $model->isNewRecord ? $ms1 = array() : $ms1 = $model->getParentOptions(true,$model->type);

            echo $form->dropDownList($model,'multiSelect1',$ms1, array(

                'multiple'=>'multiple',

                'class'=>'multi-select-transfer',

                'size'=>'20',

                'style'=>'width: 200px',

            )); ?>

            <br /><?=CHtml::link(yii::t('core','Remove').' &gt;&gt;','#',array('id'=>'remove','class'=>'multi-select-transfer button')); ?></p>

            <?=$form->error($model,'multiSelect1'); ?>

        </div>

        <div id="multiSelect2" class="multi-select-transfer">

            <p style="text-align:center"><b><?=yii::t('core','Available'); ?>:</b><br />

            <?php

            $model->isNewRecord ? $ms2 = array() : $ms2 = $model->getParentOptions(false,$model->type);

            echo $form->dropDownList($model, 'multiSelect2',$ms2, array(

                'multiple'=>'multiple',

                'class'=>'multi-select-transfer',

                'size'=>'20',

                'style'=>'width: 200px',

            )); ?>

            <br /><?=CHtml::link('&lt;&lt; '.yii::t('core','Add'),'#',array('id'=>'add','class'=>'multi-select-transfer button')); ?></p>

            <?=$form->error($model,'multiSelect2'); ?>

        </div>

    </div>


    <div class="row buttons">

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

        <?=CHtml::link(yii::t('core','Cancel'),'/user/rule/admin'); ?>

    </div>


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


</div><!-- form -->

The problem is that when the user submits the form only the changed items of the dropdownlist altered last are posted. To solve this all the $multiSelect1 dropdown items (the <option> items) have to be labeled ‘selected’ upon (when) being submitted. This way all the items of one of the dropdownlists are part of $_POST, in which case I can sort the rest out in the controller action. Adapted the following part of the code above from the example to do that but it doesn’t seem to work:


       $('form').submit(function() {

            $('#".$model->getModelName()."_multiSelect1 option').each(function(i) {

                $(this).attr(\"selected\", \"selected\");

            });

Problem is that I’m no JQuery/javascript expert so I have no idea why this doesn’t work. Anybody able to help me solve this issue? Should I change the JS code? move it to the submit button? Something else?

Interesting approach. It’s also a good candidate for creating a widget ;). But let’s check your problem first:

Can you give an example here? From your code i only see 2 dropdownlists (one to remove and one to add) + a type dropdown.

First thing that comes to my mind is the nested $().ready(function()}.

Default for the third param to registerScript is CClientScript::POS_READY (actually it is shown as "4" in the API reference).

(not tested)

/Tommy

@tri:

Good catch! :)

Solved it. Seems like I made a mistake somewhere. Here’s the javascript code that made works:


<?php Yii::app()->clientScript->registerScript('select-transfer', "

    $().ready(function() {

        $('#remove').click(function() {

            return !$('#".$model->getModelName()."_multiSelect1 option:selected').remove().appendTo('#".$model->getModelName()."_multiSelect2');

        });

        $('#add').click(function() {

            return !$('#".$model->getModelName()."_multiSelect2 option:selected').remove().appendTo('#".$model->getModelName()."_multiSelect1');

        });

        $('#rule-form').submit(function() {

            $('#".$model->getModelName()."_multiSelect1 option').each(function(i) {

                $(this).attr('selected','selected');

            });

            $('#".$model->getModelName()."_multiSelect2 option').each(function(i) {

                $(this).attr('selected','selected');

            });

        });

    });

"); ?>

It would be great if someone could convert this into a full-fledged widget and get it included by default in a future Yii release. I’m afraid my skills are insufficient but I’d be more than happy to help out by providing some code.

For those that are interested, here’s the associated Action:


class UpdateAction extends CAction

{

    public function run()

    {

        $model=$this->controller->loadModel();


        // Uncomment the following line if AJAX validation is needed

        // $this->performAjaxValidation($model);


        if(isset($_POST['Rule']))

        {

            $model->attributes=$_POST['Rule'];

            if($model->save())

            {

                if (!empty($model->multiSelect1))

                {

                    RuleHasChild::model()->deleteAll('child=:childName',array(':childName'=>$model->name));

                    foreach ($model->multiSelect1 as $n=>$name)

                    {

                        $link = new RuleHasChild;

                        $link->parent = $name;

                        $link->child = $model->name;

                        $link->save();

                    }

                }

                $this->controller->redirect(array('view','name'=>$model->name));

            }

        }


        $this->controller->render('update',array(

            'model'=>$model,

        ));

    }

}

As you can see I don’t need the items in $multiSelect2 anymore but I’ve left it in the JS code for reference purposes.

I suggest to try to build a widget on your own, it’s a perfect exercise. You’ll soon see, widgets are much easier than you may have thought :)

http://www.yiiframework.com/doc/guide/extension.create

It’s mainly a task of reorganizing the code you already have.

  • Extend CWidget and add some public properties like $id, $model, $options (this is the hard part, to make the widget really generic)

  • In the run() method, use the same code you already have for registerScript()

  • Then render a view file where you put in the markup for your dropdowns.

Creating your own widgets will lift you to the next level of developing with Yii.

Your jQuery submit() handler should return true if you want the submit to happen properly as well.