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.
What we will use ¶
1. AjaxLink: ¶
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.
2. JobController ActionAddnew: ¶
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.
3. _FormDialog: ¶
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.
Code and details ¶
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.
_form. The person's create form. ¶
~
`
php
<?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>
.....
`
~
Where to pay attention: ¶
-
$attribute
set to'jid'
-
$url
calls theActionAddnew
inJobController.php
$ajaxOptions
has to do with#jobDialog
thediv
after theajaxLink
which will contain theCJuiDialog
after the'update'
and finally last but not least the
$htmlOption
where I set anid
to theajaxLink
for avoiding some issues.
JobController. The ActionAddnew. ¶
~
`
php
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);
}
}
####Where to pay attention:
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](http://www.yiiframework.com/doc/api/CController#renderPartial-detail)
We call first the `createDialog.php` from `job/views/` which is the following.
### createDialog.php
~
```php
<?php
$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');?>
```~
####Where to pay attention:
The `'id'=>'jobDialog',` and step back to the `_form` "pay attention." :)
Here we initialize the `CJuiDialog widget` and we render the `_formDialog.php`
###_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>
```~
####Where to pay attention:
1. In the `'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` ).
2. `$("#jobDialog").dialog("close");` We close the dialog.
3. `array('id'=>'closeJobDialog')` We give unique id for this `ajaxLink` to avoid issues as we said before.
other approach
See also this tutorial, that uses the onSubmit event instead of ajaxSubmit button.
Multiple ajax submission If you have submit button on Dialog
/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(); }", ), ));
What is the class of $form?
what is the class of $form here?
<?php echo $form->labelEx($person,'jid'); ?>
onclick?
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:
'onclick'=>'if (jobAjaxComplete) { $("#jobDialog").dialog("open"); return false; } else { jobAjaxComplete = true; }',
Where jobAjaxComplete is global. So after the first request it simply opens the already created modal rather than getting it again.
Error in Controller
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
public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view','addnew'), 'users'=>array('*'), ),
Question
<?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')); ?>
What is this code doing? I couldn't understand it. Please help! Thank you!
$("#Person_jid").append(data); $("#jobDialog").dialog("close");
couldn't understand about this code
Why here 'render' => false?
CHtml::normalizeUrl(array('job/addnew','render'=>false))
Stay in form after Errors
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:
if($model->save()) { //Return an <option> and select it echo CHtml::tag('option',array ( 'value'=>$model->id, 'selected'=>true ),CHtml::encode($model->apellido),true); } else { $flag=true; } I added _else_ to let the function show again the form ... Let me know if there is another way. Best Regards
gr8
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
Additional ScriptMap Issues
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
Yii::app()->clientScript->scriptMap['jquery.js'] = false; Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;
This is an excellent write up, thank you for such a complete tutorial! Hope this helps save someone else time, too.
Check Your Rules
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:
public function accessRules() { ....... array('allow', // allow authenticated user to perform 'create' and 'update' actions 'actions'=>array('create','update','admin','delete','AddNew'), 'users'=>array('@'), ), ...... }
Good Job
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.
Great!
Thanks so much for this line:
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
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 :)
error ["jdesc cannot be blank."]}
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.
What if we have 2 forms requiring the same cjuidialog? Is this possible?
Also what is this doing exactly?
$("#Person_jid").append(data);
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?
reply to WebDevPT
Hello,
I've used this and I believe
$("#Person_jid").append(data);
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.
Datepickers in my form no longer work when I use this code
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.
Dropdownlist doesn't refresh!!!
$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.
Multiple submission
I´m having a problem when submitting multiple times.
I´d follow the steps of anandhi but couldn't solve it yet. Has anyone else the same issue?
Excellent tutorial!
Update Content With Ajax And Ajax Auto Refresh Div
Update Content With Ajax And Ajax Auto Refresh Div
double post clicking on form
When the dialog opens, and I click in the white space of the form, a POST is executed in Firebug, and then when I click the submit button another POST is executed which creates a double entry in the db.
Anyone else have this problem, solved this problem?
Person_jid
views/person/_form.php
<?php echo $form->dropDownList($person,'jid',CHtml::listData(Job::model()->findAll(),'jid','jdescr'),array('prompt'=>'Select')); ?>
This line generates
~~~
[html]
<option...
...
~~~
_Attention at id="Personjid"!
views/job/_formDialog
$("#Person_jid").append(data);
This code adds a new option-line (answer from controllers/JobController) in the
<select id="Person_jid" name="Person[jid]">
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.