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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章