Hello ppl. Even though i have a small experience with yii I though of writing this to help people which want to do something similar.
Scenario
We have a model Person how represent persons. The person has a Job. The user must select a job from a dropdownlist when he creates the person. What if the person's job is not listed in the dropdownlist and we don't want to redirect user to the job/create page. Here comes the CJuiDialog. We will create a CJuiDialog ( a modal one ;) and we will create a new job and the new job inserted will be also appended to the existing dropdowlist.
We will use an ajaxLink which will be located to the person/views/_form.php ( we will call it _form from now on ) where we create the person. The role of this ajaxLink will be to open the CJuiDialog.
The ajaxLink will call an action in the JobController with name ActionAddnew ( we will call it Addnew from now on ), which will either save the job ( after validation ) either rendering the job form.
Finally, the job form which consist of a create.php view and a _formDialog.php view, both exist under under job/views/. The _formDialog.php ( we will call it _formDialog from now on ) will contain an ajaxSubmitButton to submit the Job we want to create.
Now, I don't know from where exactly I should start to make it easier for you. I assume you have a little experience with ajaxLink etc., though I will try to be as detailed as I can.
<div class="row"> ..... <?php echo $form->labelEx($person,'jid'); <div id="job"> <?php echo $form->dropDownList($person,'jid',CHtml::listData(Job::model()->findAll(),'jid','jdescr'),array('prompt'=>'Select')); <?php echo CHtml::ajaxLink(Yii::t('job','Create Job'),$this->createUrl('job/addnew'),array( 'onclick'=>'$("#jobDialog").dialog("open"); return false;', 'update'=>'#jobDialog' ),array('id'=>'showJobDialog')); <div id="jobDialog"></div> </div> ..... </div>
$attribute set to 'jid'
$url calls the ActionAddnew in JobController.php
$ajaxOptions has to do with #jobDialog the div after the ajaxLink which will contain the CJuiDialog after the 'update'
and finally last but not least the $htmlOption where I set an id to the ajaxLink for avoiding some issues.
public function actionAddnew() { $model=new Job; // Ajax Validation enabled $this->performAjaxValidation($model); // Flag to know if we will render the form or try to add // new jon. $flag=true; if(isset($_POST['Job'])) { $flag=false; $model->attributes=$_POST['Job']; if($model->save()) { //Return an <option> and select it echo CHtml::tag('option',array ( 'value'=>$model->jid, 'selected'=>true ),CHtml::encode($model->jdescr),true); } } if($flag) { Yii::app()->clientScript->scriptMap['jquery.js'] = false; $this->renderPartial('createDialog',array('model'=>$model,),false,true); } }
The scriptMap parameter is essential. Without that line, jquery.js will be loaded again and can cause issues with javascript both already existing on the page, as well as duplicated event handlers for ajax calls run multiple times that contain their own javascript. You may want to use scriptMap to prevent other js files from loading again using '*.js' as the array key.
I think the rest is straightforward. Pay attention the last 2 parameters of renderPartial
We call first the createDialog.php from job/views/ which is the following.
$this->beginWidget('zii.widgets.jui.CJuiDialog',array( 'id'=>'jobDialog', 'options'=>array( 'title'=>Yii::t('job','Create Job'), 'autoOpen'=>true, 'modal'=>'true', 'width'=>'auto', 'height'=>'auto', ), )); echo $this->renderPartial('_formDialog', array('model'=>$model)); <?php $this->endWidget('zii.widgets.jui.CJuiDialog');
The 'id'=>'jobDialog', and step back to the _form "pay attention." :)
Here we initialize the CJuiDialog widget and we render the _formDialog.php
<div class="form" id="jobDialogForm"> <?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'job-form', 'enableAjaxValidation'=>true, )); //I have enableAjaxValidation set to true so i can validate on the fly the <p class="note">Fields with <span class="required">*</span> are required.</p> <?php echo $form->errorSummary($model); <div class="row"> <?php echo $form->labelEx($model,'jid'); <?php echo $form->textField($model,'jid',array('size'=>60,'maxlength'=>90)); <?php echo $form->error($model,'jid'); </div> <div class="row"> <?php echo $form->labelEx($model,'jdescr'); <?php echo $form->textField($model,'jdescr',array('size'=>60,'maxlength'=>180)); <?php echo $form->error($model,'jdescr'); </div> <div class="row buttons"> <?php echo CHtml::ajaxSubmitButton(Yii::t('job','Create Job'),CHtml::normalizeUrl(array('job/addnew','render'=>false)),array('success'=>'js: function(data) { $("#Person_jid").append(data); $("#jobDialog").dialog("close"); }'),array('id'=>'closeJobDialog')); </div> <?php $this->endWidget(); </div>
'success' js function the data is the what the ActioAddnew echoes.$("#Person_jid").append(data); This append the data to the 'jid' dropDownList ( check _form ).
$("#jobDialog").dialog("close"); We close the dialog.
array('id'=>'closeJobDialog') We give unique id for this ajaxLink to avoid issues as we said before.
Total 11 comments
The scriptMap parameter is essential. Without that line, jquery.js will be loaded again and can cause issues with javascript both already existing on the page, as well as duplicated event handlers for ajax calls run multiple times that contain their own javascript. You may want to use scriptMap to prevent other js files from loading again using '*.js' as the array key.
it helps! thanks a lot
Hi, i having problems with the validation, I colud see errors on fields wher I lost focus on them, but when I click submit button, the form closes and no add data to the select.
so i change this line in my addnew action:
i got this working by using the below code.
the code for ajaxLink:Here i have used the success event instead of update and it worked.
now the update div(ie the div we are going to upadate with the jquiry dialog which contains the form.). here i have placed the update div inside of jquiry dialog widget(Note:AutoOpen=false).
Note:please dont place this widget inside create.php .
Regards, sirin k http://www.sirink.tumblr.com
i tried this example but for me it loads the form without any dialog to the update div. One more thing i want to point out about the above exmpale is that there is no "onclick" event in the ajaxOptions of an ajaxLink and it can be placed inside "htmlOptions" ie the 4'th argument as an array but if we are placing an onclick event in "htmlOptions" in the above example it wont load the remote content to the update div.
Regards, sirin k http://www.sirink.tumblr.com
Why here 'render' => false?
What is this code doing? I couldn't understand it. Please help! Thank you!
Hello all, I was following the tutorial, everything was ok but the code didn't work.
I noticed that have to add the actionAddNew to the accessRules in the JobController.
If one has the same problem here is the solution, just add the acction to the access Rules.
Regards, Diego
First of all, great tutorial, really useful.
I'm a bit unclear on the "onclick" part. It's in the ajaxOptions array, but it's not an ajax option nor is it one of the extras Yii added for convenience like the "update". Perhaps at the time this tutorial was written either Yii or jQuery has a slightly different API. It could be moved to the next array, and act as the onclick for the ajaxLink, but then it tries to open a blank modal and returns so never completes the ajax request the first time.
Whenever the ajaxLink is clicked it reloads the request which also causes the script to download jquery.js, jquery-ui.min.js, and the css file all over again which is a lot for every click. Seems the "onclick" would be best placed in the htmlOptions something like:
Where jobAjaxComplete is global. So after the first request it simply opens the already created modal rather than getting it again.
what is the class of $form here? <?php echo $form->labelEx($person,'jid'); ?>
/*This will fix multiple ajax submittion problem */
$this->beginWidget('zii.widgets.jui.CJuiDialog',array( 'id'=>"dmaDialog", 'options'=>array( 'closeOnEscape'=>true, 'title'=>Yii::t("dma",'CREATE DMA'), 'autoOpen'=>true, 'modal'=>'true', 'width'=>'450px', 'height'=>'auto', 'resizable' =>false, 'close'=>"js:function(e,ui){
/* Use the below undelegate function to destroy JQuery event. Otherwise when you open dialog 1st time, It will do ajax submission 1 time, if you open 2end time, It will submit 2 times etc.. You could see the ajax submission in firebug */ jQuery('body').undelegate('#closeDmaDialog', 'click');
jQuery('#dmaDialog').empty(); }", ), ));See also this tutorial, that uses the onSubmit event instead of ajaxSubmit button.
Leave a comment
Please login to leave your comment.