Ajaxを介したグリッドの更新

こんにちは、habrasociety!



このスレッドでは、YiiでのCGridViewコンポーネントの最も適切な使用について説明します。

以下では、私が個人的に見る3つの方法について説明します。コメントであなたのアイデアを聞いてうれしいです。







だから、 タスク

複数のブロックを含むページが必要であり、そのうちの1つにはテーブル(グリッド)が必要です。

ajaxを介してグリッドをソートおよびページ分割する機能が必要です。



簡単そうですね。 Yiiが提供するものを見てみましょう。



方法1:標準CRUDジェネレーター



生成されたコードには、コントローラーの1つのアクションと1つのビューが含まれます。

コントローラー:

public function actionAdmin() { $model=new Product('search'); $model->unsetAttributes(); // clear any default values if(isset($_GET['Product'])) $model->attributes=$_GET['Product']; $this->render('index',array( 'model'=>$model, )); }
      
      





index.php

 ... <?php $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$model->search(), 'filter'=>$model, ...
      
      







一般に、すべてが機能しますが、グリッドでajaxソートまたはナビゲーションを使用するたびに、サーバーはページの完全なhtmlコードを返します! グリッドを更新するために使用されるのは、小さなHTMLピースのみです。 ページに複数の要素(たとえば、別のグリッド)が含まれている場合、サーバー側のすべての要素は無駄に処理されます。 私の意見では最善の解決策ではありません。



方法2.すべてAjaxを使用



方法1の問題を解決するには、個別のアクションとビューを作成してグリッドを形成します。 Ajaxを介してのみ動作し、renderPartial()メソッドを介してコンテンツを返します。これにより、グリッドに必要なhtmlのみが残ります。

コントローラー:

  public function actionGrid() { if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only'); $model=new Product('search'); $model->unsetAttributes(); // clear any default values if(isset($_GET['Product'])) $model->attributes=$_GET['Product']; $this->renderPartial('_grid',array( 'model'=>$model, )); }
      
      





_grid.phpにはウィジェットコードのみが含まれます。

 ... <?php $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$model->search(), 'filter'=>$model, ...
      
      





index.phpは、ページが初めてロードされたときにグリッドをプルアップします。

  <div id="grid-container"></div> yii::app()->clientScript->registerScript('load-grid', ' $("#grid-container").load("product/grid"); ');
      
      







きれいに見えますが、動作しません:) renderPartial()メソッドは、必要なJSおよびCSSファイルを返しません! HTMLのみ。

しかし、やめて! RenderPartial()には、「プロセス出力」と呼ばれる追加のパラメーターがあり、jsおよびcssを返すことができます。

コントローラーの変更:

  public function actionGrid() { if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only'); $model=new Product('search'); $model->unsetAttributes(); // clear any default values if(isset($_GET['Product'])) $model->attributes=$_GET['Product']; $this->renderPartial('_grid',array( 'model'=>$model, ), false, true); }
      
      





ページをロードし、再びbyakを確認します。ajaxを介してグリッドを更新するたびに、jquery.jsと他のスクリプトがロードを開始します。

もちろん、一度ロードする必要がありますが、renderPartial()はリクエストごとに正しく返します。

再読み込みスクリプトを無効にする方法は? これを行うには、ajax-requestsを使用してページに既にロードされているスクリプトをカットする別の拡張機能を配置できます。

出来上がり、すべてが機能します! しかし、個人的には、拡張機能なしで標準的な手段でYiiがこの問題を解決することを期待しています...



方法3. Ajaxを介したすべて(初回を除く)



しかし、通常のリクエストでグリッドを初めてロードし、次にajaxを介して更新する場合はどうでしょうか?

コントローラーでは、すべてがほとんど変更されず、追加パラメーターなしでrenderPartialのisAjaxRequestチェックを削除するだけです:

  public function actionGrid() { if(!Yii::app()->request->isAjaxRequest) throw new CHttpException('Url should be requested via ajax only'); $model=new Product('search'); $model->unsetAttributes(); // clear any default values if(isset($_GET['Product'])) $model->attributes=$_GET['Product']; $this->renderPartial('_grid',array( 'model'=>$model, )); }
      
      





メインビューindex.phpで、 actionGrid() 直接呼び出します。

  <div id="grid-container"><?php $this->actionGrid(); ?></div>
      
      





_grid.phpでは 、将来のグリッド更新のためにajaxUrlパラメーター設定します。 それ以外の場合、ajaxUrlは現在のURL(例:product / index)から取得します:

  $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$model->search() , 'filter'=>$model, 'ajaxUrl' => array('product/grid'), ...
      
      





結果を見てみましょう。 最初はグリッドは正しく読み込まれますが、ナビゲーションは機能しません!

ページリンクは、製品/グリッドではなく、製品/インデックスを指し続けます。 yiiコードを調べると、 ページネーションリンクがajaxUrlパラメーターに関連付けられておらず、現在のリクエストから取得されていることがわかりました 。 これは、最初はまったく同じではありません。 1つのアクションから別のアクションを呼び出します。 私の意見では、そのような挑戦はイデオロギー的に完全に正しいわけではありません。

しかし、どこにも行かないので、データプロバイダーのページネーションオブジェクトにrouteパラメーターを設定して修正します。

_grid.php

 <?php $dataProvider = $model->search(); $dataProvider->pagination->route = 'product/grid'; $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$dataProvider , 'filter'=>$model, 'ajaxUrl' => array($dataProvider->pagination->route), ...
      
      





これで、ほぼすべてが正常になりました。 グリッドの読み込み、並べ替え、ナビゲーションが機能しています。

しかし、軟膏にはハエがありました:

グリッドが何らかの方法でソートされ、最初のページにない場合、jsを介してその更新を呼び出します。

 $("#product-grid").yiiGridView("update");
      
      





その後、標準の並べ替えで最初のページにリセットされます。 それは残念ですね。 これは、 ajaxUrlが明示的に指定され、updateが常にリクエストを送信するためです。 ただし、ajaxUrlを指定しない場合、グリッドの更新時に現在のページと保存が保存されます ! 受信されたURLはグリッド内に保存されているため(具体的には、キーを持つdivのtitle属性に)。 ただし、ajaxUrlを指定しないことも不可能です。 その後、リクエストはソースグリッドのURL、つまり 製品/インデックス。



私に起こった唯一の解決策は、最初の(非ajax)グリッド形成で同じタイトルを変更することでした。 また、ajaxUrlをまったく指定しないでください。

結果の_grid.phpは次のようになります。

 <?php $dataProvider = $model->search(); $dataProvider->pagination->route = 'product/grid'; $this->widget('zii.widgets.grid.CGridView', array( 'id'=>'product-grid', 'dataProvider'=>$dataProvider , 'filter'=>$model, // 'ajaxUrl' => array($dataProvider->pagination->route), ... if(!yii::app()->request->isAjaxRequest) { yii::app()->clientScript->registerScript('grid-first-load', ' $("#product-grid").children(".keys").attr("title", "'.$this->createUrl($dataProvider->pagination->route).'"); '); }
      
      







これですべてが正常に機能するようになりました! 上記の松葉杖の存在にのみ恥ずかしい。



おわりに



上記の方法およびyii-projectsでのグリッドの使用に関するあなたのアイデア/コメントを聞きたいです。

ご清聴ありがとうございました!



All Articles