Yii 1.1: CJuiDialog for create new model

69 followers

Introduction

In this tutorial we will learn how to realize a create interface using a dialog.

Here is a similar tutorial that uses Ajax link to achieve the goal, but we will use a simpler and more effective approach: the event onSubmit of the form.

Scenario

Let's imagine we have a classroom with many students. If the user fills in the form of the student and there is no classroom made, he will have to create a classroom first and lose the already inserted input.

We want to allow the user to create the classroom from the form of the student, without changing pages.

Preparation of the form

First of all we need a form for creating the classroom. We can generate a Crud for classroom with gii and adapt the code to our needs.

Once we are satisfied with our form and it works with the usual submit, we can use it in a dialog.

Enhance the action create

We need to enhance the action create of the classroom controller.

Let's change it this way:

public function actionCreate()
    {
        $model=new Classroom;
 
        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);
 
        if(isset($_POST['Classroom']))
        {
            $model->attributes=$_POST['Classroom'];
            if($model->save())
            {
                if (Yii::app()->request->isAjaxRequest)
                {
                    echo CJSON::encode(array(
                        'status'=>'success', 
                        'div'=>"Classroom successfully added"
                        ));
                    exit;               
                }
                else
                    $this->redirect(array('view','id'=>$model->id));
            }
        }
 
        if (Yii::app()->request->isAjaxRequest)
        {
            echo CJSON::encode(array(
                'status'=>'failure', 
                'div'=>$this->renderPartial('_form', array('model'=>$model), true)));
            exit;               
        }
        else
            $this->render('create',array('model'=>$model,));
    }

We add some small changes: in case of ajax request we write a json encoded array.

In this array we return a status (failure/success) and the whole form created with renderPartial.

The dialog

Now the back-end is done, let's write the dialog itself.

In the form of the student somewhere we add this code:

<?php echo CHtml::link('Create classroom', "",  // the link for open the dialog
    array(
        'style'=>'cursor: pointer; text-decoration: underline;',
        'onclick'=>"{addClassroom(); $('#dialogClassroom').dialog('open');}"));?>
 
<?php
$this->beginWidget('zii.widgets.jui.CJuiDialog', array( // the dialog
    'id'=>'dialogClassroom',
    'options'=>array(
        'title'=>'Create classroom',
        'autoOpen'=>false,
        'modal'=>true,
        'width'=>550,
        'height'=>470,
    ),
));?>
<div class="divForForm"></div>
 
<?php $this->endWidget();?>
 
<script type="text/javascript">
// here is the magic
function addClassroom()
{
    <?php echo CHtml::ajax(array(
            'url'=>array('classroom/create'),
            'data'=> "js:$(this).serialize()",
            'type'=>'post',
            'dataType'=>'json',
            'success'=>"function(data)
            {
                if (data.status == 'failure')
                {
                    $('#dialogClassroom div.divForForm').html(data.div);
                          // Here is the trick: on submit-> once again this function!
                    $('#dialogClassroom div.divForForm form').submit(addClassroom);
                }
                else
                {
                    $('#dialogClassroom div.divForForm').html(data.div);
                    setTimeout(\"$('#dialogClassroom').dialog('close') \",3000);
                }
 
            } ",
            ))?>;
    return false; 
 
}
 
</script>

And that's all. In this code we have:

  • A link for open the dialog
  • the dialog itself, with a div inside that will be replaced with ajax
  • the javascript function addClassroom().

This function fires an ajax request to the action create we prepared in the previous step.

The returned form will be placed in the dialog (with eventually, all errors and so on) in case of status failure, in case of status success in the example we replace the div and we close the dialog after 3 seconds.

If you use this system in the form for student, you can return, for example, the id of the newly inserted classroom and select it automatically in a drop down list.

Summary

To make a long story short:

  • Prepare the usual creation with gii generated code
  • Change the action create for answer to Ajax requests
  • Place the link/dialog/js wherever you want.

This methodology is very comfortable because it changes anything in the code of the _form, so any eventually added field in classroom will be available in both standard and dialog insert.

Total 20 comments

#19047 report it
xNicox at 2015/03/03 08:12pm
Refresh...

hi @erand, i think they reload the page ...

anyway, i'm happy to help !

you'r welcome

#19046 report it
erand at 2015/03/03 03:48pm
Refresh...

Hi @xNicox

I was taking care of other issues in my app, and just came back to this... Thanks to your help, it is working now...I am just wondering how was it working for others without appending the new tag!! Or was it only me that was missing it...

Anyway...thank you @xNicox

#18987 report it
xNicox at 2015/02/18 03:25pm
Refresh...

hi, @erand, the input in html is created with this line of yii:

echo $form->dropDownList($model, 'entidad_id', GxHtml::listDataEx(Entidad::model()->findAllAttributes(null, true, $criteria))); ?>

because $model is "prestamo", the html is: ....

So, there is your html id!

#18967 report it
erand at 2015/02/14 08:11am
Refresh...

Hi @xNicox,

Can you please share here your code of that html element (dropdownlist) whose ID is #Prestamo_entidad_id?

#18961 report it
xNicox at 2015/02/12 03:31pm
Refresh...

hi @erand, the html ID is the "Select" or "combo" in the form!. The action in the controller return a new "" element of the "".

I hope it helps! Best Regards

#18960 report it
erand at 2015/02/12 02:55pm
Refresh...

Hello @xNicox,

Thank you for sharing. I can't get it working cause I don't understand the new line you added:

$('#Prestamo_entidad_id').append(data.tag); //<-- new

Which element is this: #Prestamo_entidad_id ?

Thank you in advance.

#18848 report it
xNicox at 2015/01/23 04:50am
Refresh...

hi @erand, i think I solved the problem.

I add this in the addNew Method, see the new 'tag' element in the JSON answer:

echo CJSON::encode(array(
              'status'=>'success', 
              'div'=>'Cliente creado exitosamente',
              'tag'=> CHtml::tag('option',
                             array ('value'=>$model->id,'selected'=>true),
                             CHtml::encode($model->apellidoynombre),true),                                                           ));

Also in the form (_form.php) where is the button.

...
                else
                {
                    $('#dialogClassroom div.divForForm').html(data.div);
                    //alert(data.tag);
                    $('#Prestamo_entidad_id').append(data.tag); //<-- new                      
                    setTimeout(\"$('#dialogClassroom').dialog('close') \",3000);
                }
...

I hope it helps ! Best Regards.

#18779 report it
xNicox at 2015/01/05 07:40am
refresh

Hi,@erand, I think what you need is a diferent approach. I have the same issue as you, and I use another tutorial that I don't find right know, but basically you have to return, on success, an HTML tag.

if ($model->save()) {
                    //Return an <option> and select it
                            echo CHtml::tag('option',array (
                                'value'=>$model->id,
                                'selected'=>true
                            ),CHtml::encode($model->ApellidoYNombrePapa),true);
 
                }

This routines return a text, in the JSON array.

Also I have some issues with validations and error processing... If you can mix and figured out how to: create a link to open a dialog make this dialog refresh if some rule validation fails. and on success add a new entry in the combo !

please share, best regards

PS: Sorry for my poor english.

#18771 report it
erand at 2015/01/03 03:25pm
Refresh...

The new element is added in db, but not in the dropdownlist...I have to refresh the page to see the new element in the dropdown...what could be the problem?

#17692 report it
seletar6 at 2014/07/15 04:08am
zii.widgets.jui.CJuiDatePicker does not work on the Popup form

Just in case some of you encounter the same problem. Pls see following,

if (Yii::app()->request->isAjaxRequest) {
            echo CJSON::encode(array(
                'status' => 'failure',
                'div' => $this->renderPartial('_form', array('model' => $model), true, true)));
            exit;
        } else
            $this->render('create', array(
                'model' => $model,
            ));

http://stackoverflow.com/questions/13698645/cjuidatepicker-widget-in-yii-framework

#16988 report it
Rabb T. at 2014/04/18 04:16pm
When CSRF validation is enabled

I spent half a day figuring out why it was not working for me, so I'd like to share: Here is what works for me when CSRF is enabled:

function addClassroom()
{
    var theData = $('#dialogClassroom div.divForForm form').serializeArray();
    theData.push({name:'<?php echo Yii::app()->request->csrfTokenName ?>', value:'<?php echo Yii::app()->request->csrfToken ?>'});
 
    <?php echo CHtml::ajax(array(
            'url'=>array('classroom/create'),
            'data'=> "js:theData",
            ...
#16869 report it
Bibi40k at 2014/04/05 01:36am
Giix Problem

If anyone uses Giix probably they get a blank popup so this is the trick:

giix-components/GxController.php line 160

if (Yii::app()->getRequest()->getIsAjaxRequest() && (($form === null) || ($_POST['ajax'] == $form)))

change: ($_POST['ajax'] == $form) to: (isset($_POST['ajax']) && $_POST['ajax'] == $form)

#14157 report it
Rolando Rocha at 2013/07/23 11:15am
Form Validation

Hi, First of all, thank you for share this tutorial! I have a question to make. What are supposed to happen when I don't respect the rules validations? In my case I was redirected to the normal action with the rules messages! I failed in some code?

Thanks!

#13648 report it
zaccaria at 2013/06/14 01:36am
re arrigonfr

Check first of all the json response with firebug, probably you have an error in the controller.

#13631 report it
arrigonfr at 2013/06/12 05:03pm
something doesn't work

I've practically copy/pasted the code, only changing "Classroom" for "People" where I should. The model window comes up, i type the code, i click the button, the dialog closes but the information won't save.

#13623 report it
code4d1 at 2013/06/12 04:59am
problem with dropdown dependent

thanks for tutorial,

I was experiencing with my dropdown dependent. when click on the dropdown country, the cities is not shown.

solve with change a little in actionCreate:

'div'=>$this->renderPartial('_form', array('model'=>$model), true)));

to :

'div'=>$this->renderPartial('_form', array('model'=>$model), true, true)));

its work for me, hope help any body else.

edit !!

another issue come up after that change. "new classroom" link only working for first click, so the second click without refreshing the student form will not open the classroom dialog.

solve with a little change again in actionCreate :

if (Yii::app()->request->isAjaxRequest)
{                    
   echo CJSON::encode(array(
      'status'=>'failure', 
      'div'=>$this->renderPartial('_form', array('model'=>$model), true, true)));
       exit;               
}

to:

if (Yii::app()->request->isAjaxRequest)
{                
   Yii::app()->clientScript->scriptMap['jquery.js'] = false;   
   echo CJSON::encode(array(
      'status'=>'failure', 
      'div'=>$this->renderPartial('_form', array('model'=>$model), true, true)));
       exit;               
}

hope it help. please dont kick my ass if I do wrong...

#12672 report it
nfdevil at 2013/04/04 02:57pm
Nesting forms isn't allowed

I didn't get this to work at first. The form element was being deleted by jquery's html() method in Chrome. So I went to the Yii IRC and we solved it there. Found out that nested forms aren't allowed ;)

To fix this, just put the div where your 'classroom creation' form will be in

<div class="divForForm"></div>

at the END of the student's _form.php, so under the endWidget of the student form (where the form tag is being closed)

#12222 report it
Andrés at 2013/03/07 08:56am
Not working with CJuiAutocomplete

Thank you very much for this great article. I've been able to implement the code and I see the dialog and save a new record. However, in my create view I've two CJuiAutocomplete that aren't working and I don't know why. Thank you for any clue.

#12220 report it
Alaa Abdelhaq at 2013/03/07 08:05am
Problem with 'data'=> "js:$(this).serialize()",

I have a problem when I wanna send some variables to be displayed inside the form Instead of using

'data'=> "js:$(this).serialize()",

I use this

'data'=> array(
                    'time_from'=> 'js:start.format("HH:MM:00")', 
                    'time_to'=> 'js:end.format("HH:MM:00")', 
                    'channel_id' => $channel->id,
                    'schedule_date'=>  'js:start.format("yyyy-mm-dd")'
                ),

Its working fine but whne I submit the form in the dialog it takes me to the full page instead in reloading form inside the dialog! How can I fix this? Thanks!

#11825 report it
broker at 2013/02/06 08:15am
dialog options

Hi, In order to set dialog options this line formDialog.js#13 has to be changed like following. dialog.dialog(); ==> dialog.dialog(options);

Leave a comment

Please to leave your comment.

Write new article