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 18 comments
$model-save() save my data into database table, but it returns FALSE!!!!!
What happen???
EDIT!!!
I disabled ajaxValidation and it works!
Thanks for the article.
This wiki is great: I have used this code and it works fine but the only problem is that I have 2 datepickers on my form (CJuiDatePickers) and they do not work each time I use the code to create a new client. When I do not use the code (that is, client exists already) the datepickers work fine. Can anyone suggest what I should do. I tried to reactivate the datepickers by using afterajaxupdate but it works only intermittently.
Hello, I've used this and I believe
is used to append the newly created item to the dropdownlist.
Person_jid is the html id for the dropdownlist in you r_form.php
I hope that I don't say a stupid thing and that I help you.
I am sorry I can not reply to the rest of your question.
AGAIN I need to remove AJAXVALIDATION for this to work. anyone knows why ? best regards.
Also what is this doing exactly?
Do I need to use exacly "ModelA_FieldNameInModelA" in order for this to work?
I would like to have 2 Models containing the same add new for a specific field, for example Cities for Persons and for Companies. What would be a good way to implement this?
I have this error message that appears in the div "jobDialog" {"Job_jdesc":["jdesc cannot be blank."]} and the dialog does not open.
UPDATE: The error disappears and the dialog opens if I remove $this->performAjaxValidation($model); from the actionAddnew in the job controller... but then the new record is done in database but not added to the dropdownlist. I have to refresh the page...
any help ? thxs.
Thanks so much for this line:
I've been trying to figure out why my CJuiDialog won't come up when another Ajax button was clicked first... Have been trying to figure it out for hours so this just made my day!
Thanks a lot :)
I'm following the tutorial step by step, and the dialog is shows up, but submit button did not save the new entry and did not shows into the drop down list.
any one have a solution for me.
If you are unable to view your modal/form/add data make sure that you have added the action to your accessRules and granted yourself sufficient permission to access this action.
Example is below:
To all those that may still have problems:
What happened on mine is after the dialog came up successfully Chrome would throw a TypeError when I submitted the data. I found the conflict was NOT with jquery.js but infact was jquery.min.js.
I added the following in the controller /addnew
This is an excellent write up, thank you for such a complete tutorial! Hope this helps save someone else time, too.
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:
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.