加载中...

yii_wiki_216_update-delete-model-with-cjuidialog-works-in-cgridview(通过CJuiDialog在CGridView中CRUD)


/*****
Update/delete model with CJuiDialog (works in CGridView) 

http://www.yiiframework.com/wiki/216/update-delete-model-with-cjuidialog-works-in-cgridview

translated by php攻城师

http://blog.csdn.net/phpgcs
 
Introduction
Controller code
Create action
Update action
Delete action
View Code(for CGridView and simple links)
Gii Code Generator
Summary

****/

/***
Introduction 
***/
我的方法基于 这篇wiki http://www.yiiframework.com/wiki/145/cjuidialog-for-create-new-model/

这篇教程将向你介绍 如何  创建 Ajax dialog 来 对model 进行 CRUD 的操作。
适用于 简单的 links , CGridView button column links, 用最少的代码并且在JS关闭的情况下也可以完美的实现。

现在已经有可用的扩展 extensions 了(本人开发的): EUpdateDialog
http://www.yiiframework.com/extension/eupdatedialog/
但是需要注意的是, 对于(该扩展)最新的代码更新, 你应该仔细检查。
因为需要花费时间来更新2个相似的但是有些微不同的文档(extension 和 this wiki), 我可能不会更新这篇教程(除非是很重要的更新)。
因此我的建议是 阅读这篇教程搞清楚工作原理, 然后检查 extension 文章和源代码。
带来的不方便,我感到很抱歉, 但是我认为花费的这些时间 如果用于更新 extension 本身会更好。

/****

<< Controller code

	  <<Create action
		Update action
		Delete action
View Code
Gii Code Generator
Summary

***/
Create action 

public function actionCreate()
{
  $model = new ModelName;
  if( isset( $_POST['ModelName'] ) )
  {
    $model->attributes = $_POST['ModelName'];
    if( $model->save() )
    {
      if( Yii::app()->request->isAjaxRequest )
      {
        // Stop jQuery from re-initialization
        Yii::app()->clientScript->scriptMap['jquery.js'] = false;
 
        echo CJSON::encode( array(
          'status' => 'success',
          'content' => 'ModelName successfully created',
        ));
        exit;
      }
      else
        $this->redirect( array( 'view', 'id' => $model->id ) );
    }
  }
 
  if( Yii::app()->request->isAjaxRequest )
  {
    // Stop jQuery from re-initialization
    Yii::app()->clientScript->scriptMap['jquery.js'] = false;
 
    echo CJSON::encode( array(
      'status' => 'failure',
      'content' => $this->renderPartial( '_form', array(
        'model' => $model ), true, true ),
    ));
    exit;
  }
  else
    $this->render( 'create', array( 'model' => $model ) );
}

这样以来, 就可以简单地 save model 并 根据请求的类型来展示合适的内容。
重点是, 
1, 你需要用scriptMap 禁用 jQuery ,来阻止 重新初始化 
2, 如果你在 form 视图中使用 JS 代码的话,你要设置  renderPartial $processOutput parameter to true


/****
<< Controller code

	    Create action
	  <<Update action
		Delete action
View Code
Gii Code Generator
Summary

****/


Update action 跟 create action 类似, 只有2个地方不同:
1, 你需要先 load model
2, 你需要  change success message.


public function actionUpdate()
{
  $model = $this->loadModel();
  if( isset( $_POST['ModelName'] ) )
  {
    $model->attributes = $_POST['ModelName'];
    if( $model->save() )
    {
      if( Yii::app()->request->isAjaxRequest )
      {
        // Stop jQuery from re-initialization
        Yii::app()->clientScript->scriptMap['jquery.js'] = false;
 
        echo CJSON::encode( array(
          'status' => 'success',
          'content' => 'ModelName successfully updated',
        ));
        exit;
      }
      else
        $this->redirect( array( 'view', 'id' => $model->id ) );
    }
  }
 
  if( Yii::app()->request->isAjaxRequest )
  {
    // Stop jQuery from re-initialization
    Yii::app()->clientScript->scriptMap['jquery.js'] = false;
 
    echo CJSON::encode( array(
      'status' => 'failure',
      'content' => $this->renderPartial( '_form', array(
        'model' => $model ), true, true ),
    ));
    exit;
  }
  else
    $this->render( 'update', array( 'model' => $model ) );
}


/****
<< Controller code

	    Create action
	    Update action
	  <<Delete action
View Code
Gii Code Generator
Summary

****/

不像默认的Yii 展示JS确认对话框那样的动作 ,这里展示了普通的 HTML 表单;这种方式 的好处在于, 即使JS 功能被禁用 了, 你仍然可以 delete model

public function actionDelete()
{
  $model = $this->loadModel();
  if( Yii::app()->request->isAjaxRequest )
  {
    // Stop jQuery from re-initialization
    Yii::app()->clientScript->scriptMap['jquery.js'] = false;
 
    if( isset( $_POST['action'] ) && $_POST['action'] == 'confirmDelete' )
    {
      $model->delete();
      echo CJSON::encode( array(
        'status' => 'success',
        'content' => 'Deleted succussfully',
      ));
      exit;
    }
    else if( isset( $_POST['action'] ) )
    {
      echo CJSON::encode( array(
        'status' => 'canceled',
        'content' => 'Deletion canceled',
      ));
      exit;
    }
    else
    {
      echo CJSON::encode( array(
        'status' => 'failure',
        'content' => $this->renderPartial( 'delete', array(
          'model' => $model ), true, true ),
      ));
      exit;
    }
  }
  else
  {
    if( isset( $_POST['confirmDelete'] ) )
    {
      $model->delete();
      $this->redirect( array( 'admin' ) );
    }
    else if( isset( $_POST['denyDelete'] ) )
      $this->redirect( array( 'view', 'id' => $model->id ) );
    else
      $this->render( 'delete', array( 'model' => $model ) );
  }
}

这个动作 检查是否是Ajax 请求,
如果是, 会检查 用户是 确认/拒绝 了删除model的请求,如果两者都不是, 那就再渲染一个 confirmation form 的Delete Confirmation 视图。 
这个 Delete Confirmation 视图 需要至少 2个提交按钮(确认, 拒绝)。

如果 浏览器禁用了 JS , Delete Confirmation 视图 将会正常地被渲染, 从而同样可以达到delete model 的目的。

// You need to have a form in your delete view file!
<?php $form = $this->beginWidget( 'CActiveForm', array(
  'id' => 'location-delete-form',
  'enableAjaxValidation' => false,
  'focus' => '#confirmDelete',
)); ?>
 
<div class="buttons">
  <?php 
  echo CHtml::submitButton( 'Yes', array( 'name' => 'confirmDelete', 
    'id' => 'confirmDelete' ) );
  echo CHtml::submitButton( 'No', array( 'name' => 'denyDelete' ) ); 
  ?>
 
  <?php
  /* !!! Or you can use jQuery UI buttons, makes no difference !!!
  $this->widget( 'zii.widgets.jui.CJuiButton', array(
    'name' => 'confirmDelete',
    'caption' => 'Yes',
  ));
  $this->widget( 'zii.widgets.jui.CJuiButton', array(
    'name' => 'denyDelete',
    'caption' => 'No',
  ));*/
  ?>
</div>
 
<?php $this->endWidget(); ?>

/****
translated by php攻城师

http://blog.csdn.net/phpgcs


 Controller code

	    Create action
	    Update action
	  Delete action

<< View Code
Gii Code Generator
Summary

****/


如果你要在 CGridView widget 里面使用 上面的功能, 代码如下:

<?php $this->widget( 'zii.widgets.grid.CGridView', array(
  // # your widget settings here #
  'columns' => array(
    // # your columns #
    array(
      'class' => 'CButtonColumn',
      'header' => 'Action',
      'deleteButtonUrl' => 'Yii::app()->createUrl( 
        "/admin/location/delete", 
        array( "id" => $data->primaryKey ) )',
      'buttons' => array(
        'delete' => array(
          'click' => "function( e ){
            e.preventDefault();
            $( '#update-dialog' ).children( ':eq(0)' ).empty(); // Stop auto POST
            updateDialog( $( this ).attr( 'href' ) );
            $( '#update-dialog' )
              .dialog( { title: 'Delete confirmation' } )
              .dialog( 'open' ); }",
        ),
        'update' => array(
          'click' => "function( e ){
            e.preventDefault();
            $( '#update-dialog' ).children( ':eq(0)' ).empty(); // Stop auto POST
            updateDialog( $( this ).attr( 'href' ) );
            $( '#update-dialog' )
              .dialog( { title: 'Update' } )
              .dialog( 'open' ); }",
        ),
      ),
    ),
  ),
)); ?>

这段代码 更改 delete 按钮 重定向到 delete confirmation 从而可以在无JS 的情况下工作。
也将 delete 和 update 按钮的点击属性替换为 自定义的函数, 这个函数 禁止了 link 的默认行为 , 清除了 dialog 的内容, 把 链接url 给了即将打开的dialog , 最后打开dialog。



<?php
$this->beginWidget( 'zii.widgets.jui.CJuiDialog', array(
  'id' => 'update-dialog',
  'options' => array(
    'title' => 'Dialog',
    'autoOpen' => false,
    'modal' => true,
    'width' => 550,
    'resizable' => false,
  ),
)); ?>
<div class="update-dialog-content"></div>
<?php $this->endWidget(); ?>

这段代码 初始化了CJuiDialog 从而可以在我们需要的时候随时调用。



<?php
$updateJS = CHtml::ajax( array(
  'url' => "js:url",
  'data' => "js:form.serialize() + action",
  'type' => 'post',
  'dataType' => 'json',
  'success' => "function( data )
  {
    if( data.status == 'failure' )
    {
      $( '#update-dialog div.update-dialog-content' ).html( data.content );
      $( '#update-dialog div.update-dialog-content form input[type=submit]' )
        .die() // Stop from re-binding event handlers
        .live( 'click', function( e ){ // Send clicked button value
          e.preventDefault();
          updateDialog( false, $( this ).attr( 'name' ) );
      });
    }
    else
    {
      $( '#update-dialog div.update-dialog-content' ).html( data.content );
      if( data.status == 'success' ) // Update all grid views on success
      {
        $( 'div.grid-view' ).each( function(){ // Change the selector if you use different class or element
          $.fn.yiiGridView.update( $( this ).attr( 'id' ) );
        });
      }
      setTimeout( \"$( '#update-dialog' ).dialog( 'close' ).children( ':eq(0)' ).empty();\", 1000 );
    }
  }"
)); ?>

这段代码将 ajax 保存在php变量中 。

如果请求失败, 意味着 what we have a form to display it adds retrieved code to dialog,对 submint 按钮 去除所有的 live event handlers 。 
(否则你下此打开 dialog 将会提交 2个请求。。然后3个。。等等)然后再重新把 live event handlers  赋给 submint 按钮。

然后用户点击了 submit 按钮, 
Then user clicks submit button, it stops the form from submiting and sends his name attribute to update function.

如果返回的 status 不是 'failure', 将会 把受到的数据 展示在dialog中. 
进而如果 status 是 'success' , 意味着 model 已经成功地  deleted/updated/created , 那么将会更新所有的 grid view widgets。
最后增加一个 timeout 函数关闭 并清除 dialog.

<?php
Yii::app()->clientScript->registerScript( 'updateDialog', "
function updateDialog( url, act )
{
  var action = '';
  var form = $( '#update-dialog div.update-dialog-content form' );
  if( url == false )
  {
    action = '&action=' + act;
    url = form.attr( 'action' );
  }
  {$updateJS}
}" ); ?>

这个函数 完成了所有的更新。
首先,它设置了 需要的 变量, 然后检查url 参数是否提供了。
如果 提供了, 将展示合适的 form ;
如果没有提供, 即 url 是 false , 意味着 form 已经被提交, 而它将 设置 action varialbe , 从 form 得到 url 并做出合适的 ajax 请求。

<?php
Yii::app()->clientScript->registerScript( 'updateDialogCreate', "
jQuery( function($){
    $( 'a.update-dialog-create' ).bind( 'click', function( e ){
      e.preventDefault();
      $( '#update-dialog' ).children( ':eq(0)' ).empty();
      updateDialog( $( this ).attr( 'href' ) );
      $( '#update-dialog' )
        .dialog( { title: 'Create' } )
        .dialog( 'open' );
    });
});
" );
?>

为了 给 links 添加 dialog 功能 , 你只需要添加 把上面这段 script 即可。(这段script 为所有的 links  a.update-dialog-create 绑定了处理程序的点击事件)



/****
translated by php攻城师

http://blog.csdn.net/phpgcs


 Controller code

	    Create action
	    Update action
	    Delete action

View Code
<< Gii Code Generator
Summary

****/

默认的 由 gii 生成的代码 需要做一些修改。

public function loadModel()
{
  if( $this->_model === null )
  {
    if( isset( $_GET['id'] ) )
      $this->_model = ModelName::model()->findByPk( (int)$_GET['id'] );
    if( $this->_model === null )
      throw new CHttpException( 404, 'The requested page does not exist.' );
  }
  return $this->_model;
}


还没有评论.