Yii 1.1: CGridView: Update/create records in a CJuiDialog

27 followers

Note: This code is now part of the extension quickdlgs

My article Display the full record in a CJuiDialog uses ajax to view a record in dialog on clicking the 'view-icon'.

Other authors use ajax too for update/insert:

Here is a solution that uses an iframe within the dialog. It's easy to implement in a few steps.

I use the 'Address' example like the one in my last article, but you can copy/paste the new code of views/admin.php and actionUpdate/Create unchanged for usage with any other model.

Step 1

You have to generate an iframe-layout (layouts/iframe.php) that includes at least the css-files for the form. You can copy your main-layout and remove unnecessary code.

Tip: You can use this layout to display other content from your site within a dialog too.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="language" content="de" />
 
    <!-- blueprint CSS framework -->
    <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/screen.css" media="screen, projection" />
    <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/print.css" media="print" />
    <!--[if lt IE 8]>
    <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/ie.css" media="screen, projection" />
    <![endif]-->
 
    <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/main.css" />
    <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/form.css" />
    <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/custom.css" />
 
</head>
<body>
<div id="page">
    <?php echo $content; ?>
</body>
</html>

Step 2

Alter the code of views/admin.php.

You have to add the code for the CJuiDialog and change the behavior of the CButtonColumn update-icon.

The click function sets the source for the iframe and opens the dialog. It's important to 'return false' onclick.

The 'gridId' is submitted to make the code reusable for other models too.

....
<?php $this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'address-grid',
    'dataProvider'=>$model->search(),
    'filter'=>$model,
    'columns'=>array(
        'ID',
        'FIRSTNAME',
        'LASTNAME',
        ...
        array(
            'class'=>'CButtonColumn',
            //--------------------- begin new code --------------------------
            'buttons'=>array(
                        'update'=>
                            array(
                                    'url'=>'$this->grid->controller->createUrl("update", array("id"=>$data->primaryKey,"asDialog"=>1,"gridId"=>$this->grid->id))',
                                    'click'=>'function(){$("#cru-frame").attr("src",$(this).attr("href")); $("#cru-dialog").dialog("open");  return false;}',
                                ),
                            ),
            //--------------------- end new code --------------------------
        ),
    ),
));?>
 
 
<?php
//--------------------- begin new code --------------------------
   // add the (closed) dialog for the iframe
    $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
    'id'=>'cru-dialog',
    'options'=>array(
        'title'=>'Detail view',
        'autoOpen'=>false,
        'modal'=>false,
        'width'=>750,
        'height'=>800,
    ),
    ));
?>
<iframe id="cru-frame" width="100%" height="100%"></iframe>
<?php
 
$this->endWidget();
//--------------------- end new code --------------------------
?>

Step 3

Change the code of the actionUpdate of the controller like below. If the get-param 'asDialog' is not set, the method works as usual.

Otherwise:

  • The layout is set to '//layouts/iframe'
  • After saving the model:
    • Close the dialog
    • Reset the iframe source. Otherwise the last opened record is shown until the current is loaded.
    • Refresh the gridview
public function actionUpdate($id)
{
    $model=$this->loadModel($id);
 
    // Uncomment the following line if AJAX validation is needed
    // $this->performAjaxValidation($model);
 
    if(isset($_POST['Address']))
    {
        $model->attributes=$_POST['Address'];
        if($model->save())
            //----- begin new code --------------------
            if (!empty($_GET['asDialog']))
            {
                //Close the dialog, reset the iframe and update the grid
                echo CHtml::script("window.parent.$('#cru-dialog').dialog('close');window.parent.$('#cru-frame').attr('src','');window.parent.$.fn.yiiGridView.update('{$_GET['gridId']}');");
                Yii::app()->end();
            }
            else
            //----- end new code --------------------
 
            $this->redirect(array('view','id'=>$model->ADDRESS));
    }
 
    //----- begin new code --------------------
    if (!empty($_GET['asDialog']))
        $this->layout = '//layouts/iframe';
    //----- end new code --------------------
 
    $this->render('update',array(
        'model'=>$model,
    ));
}

That's all about updating.

And what's about the action create?

You can add a link below the caption of the admin-view.

<h1>Manage Addresses</h1>
 
<?php
 $createUrl = $this->createUrl('create',array("asDialog"=>1,"gridId"=>'address-grid'));
 echo CHtml::link('Create Address','#',array('onclick'=>"$('#cru-frame').attr('src','$createUrl '); $('#cru-dialog').dialog('open');"));
?>

Or you set the 'createUrl' and 'onclick' like above in the operations menu if you use the default columns2 layout.

The code-snippets from the actionUpdate work unchanged in the actionCreate too. Alter the code of actionCreate exactly the same as the code from actionUpdate above.

Tip

Add a cancel-button in your _form.php in the button row.

<div class="row buttons">
        <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
        <?php echo CHtml::button('Cancel',array('onclick'=>"window.parent.$('#cru-dialog').dialog('close');window.parent.$('#cru-frame').attr('src','');")); ?>
    </div>

But if you use the update/insert form in single page mode too, you have to check if the form is shown in the dialog or not, maybe by submitting the variable 'asDialog' to the _form.php.

Total 11 comments

#14280 report it
Gerhard Liebenberg at 2013/08/01 05:21am
Tip: communication from nested child iframe to parent iframe

My main page uses the layouts/main.php file.

In main.php, I have iframe1.

In the javascript of this main page, I have this function:

$(document).bind('update-iframe1', function(event, $url){
    $('#iframe1').attr("src", $url);
});

Views that are displayed in iframe1 are rendered with the layouts/iframe1.php file.

Inside layouts/iframe1.php I have iframe2.

In the javascript of layouts/iframe1.php, I have this function:

$(document).bind('update-iframe1', function(event, $url) { 
    parent.$(parent.document).trigger('update-iframe1', $url);
});

In a view in iframe2, I have this url and button:

$url = generate the url here / use a received url / use current url;
 
echo CHtml::button('My Button', array(
    'onclick'=>"
        parent.$(parent.document).trigger('update-iframe1', '$url');
    ",
));

So the button in view (in iframe2), triggers 'update-iframe1' (in iframe1), which triggers 'update-iframe1' (in main page), which updates iframe1 (using the url).

So now, after I created a new record in dialog2, I can update the treeview in dialog1.

Ps. I give al the functions the same name: 'update-iframe1'. So I don't have to worry about different function names in different nested iframes.

#13039 report it
Dineshkumar at 2013/04/30 03:49am
Thanks!

This is a great Tip to me !!!

#13038 report it
dhanakumar at 2013/04/30 03:46am
Thanks!

hello Joblo, ~~~ It is an excellent post,I have been struggling for long time by this issue.This post is really helpful to me.Continue your good work.

Regards , Dhana and Dinesh

~~~http://www.yiiframework.com/site/markdownHelp/

#11368 report it
Hipogea at 2013/01/09 09:31pm
EXCELLENT

Thanks, it was that I was finding, long time ago, it's helpful to create matchodes helpers, to make more easy the input data

....

#11194 report it
anilherath at 2012/12/25 03:09am
The best tutorial I ever seen.....!

Great explanation. It's work on the first try. Thank you very much for sharing joblo.

#9014 report it
Gerhard Liebenberg at 2012/07/12 03:58pm
Excellent

If you want to display complex views (containing CGridViews etc.) inside a CJuiDialog, then this wiki is simply the best.

How to prevent flickering and how to re-size the dialog:

I put the dialog inside the "boby" section of views\layouts\main.php

That way, it is already included and ready for use in all views. So you don't have to include it again in your admin (and other) views.

<div class="row-fluid">
    <?php
        $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
            'id'=>'dialog1',
            'options'=>array(
                'autoOpen'=>false,
                'modal'=>true,
                'width'=>'10%', /*only a default*/
                'height'=>'10%', /*only a default*/
                'position'=>'top', /*only a default*/
                'open'=> 'js:function(event, ui) { $(".ui-dialog-titlebar-close").hide(); }', /* hide default close button*/
                                                ),
        ));
    ?>
        <!-- Make iframe width/height = 0% to prevent flickering. Enlarge it again in button js. -->
        <div class="row-fluid" span12">
            <iframe id="iframe1" width="0%" height="0%"></iframe>
        </div>
    <?php $this->endWidget(); ?>
</div>

I have a gridview on my main page. If you click one of the gridview's update buttons, it calls a js function which opens and re-size the dialog. Here is the gridview button code:

'update'=>array(
    'label'=>'Update Master Record',
    'icon' => 'icon-pencil icon-white',
    'url'=>'$this->grid->controller->createUrl("update", array(
        "parentID"=>$data->primaryKey,
        "asDialogFlag"=>1,
        "gridId"=>$this->grid->id)
    )',
 
    'click'=>'function(){
        initialiseDialog("#dialog1", "#iframe1", $(this).attr("href"));
        return false;
    }',
),

This is how I re-size my dialog after it is opened - so that it always will display almost full screen.

function initialiseDialog(dialog, iframe, url)
{
    $(dialog).dialog("option", "title", "Loading...");
    $(dialog).dialog("option", "width", $(window).width()-20);
    $(dialog).dialog("option", "height", $(window).height()-20);
    $(dialog).css("position","middle","top");
 
    $(window).scrollTop(0); /* Scroll to the main page's top */
    $(dialog).dialog("open");
 
    /* Set iframe size after dialog was opened */   
    $(iframe).attr("src",url);  
    $(iframe).css("width", $(dialog).width()-16);   
    $(iframe).css("height", $(dialog).height()-10);
    $(iframe).css("position","middle","top");
}

Prevent the main window (behind the dialog) from scrolling with the dialog:

$("#dialog1").mouseenter(function(){
   $("body").css("overflow", "hidden"); 
}).mouseleave(function(){
   $("body").css("overflow", "visible");
});
#7442 report it
docnewman at 2012/03/22 11:19pm
Gracias!

I was looking for this

#7255 report it
kkkyka6s at 2012/03/07 10:04am
no cancel

The cancel button as within the last tip, simply don't work in my case. It seems that the dialog('close') don't react

Achim

#6688 report it
ernani at 2012/01/28 02:57pm
Thank you so much!

You can't imagine how many hours I've spent to accomplish this. As a last resort, I implemented it using fancybox, but it wasn't that flexible a solution as using CJuiDialog.

#5871 report it
Nacesprin at 2011/11/21 01:49pm
Thanks!

This is a great Tip!!

#5834 report it
xNicox at 2011/11/17 08:43pm
Excelent !

Good tutorial, works on the first try !!

Leave a comment

Please to leave your comment.

Write new article
  • Written by: Joblo
  • Category: Tips
  • Yii Version: 1.1
  • Votes: +14
  • Viewed: 36,591 times
  • Created on: Oct 23, 2011
  • Last updated: Jun 19, 2012
  • Tags: CGridView, CJuiDialog