Technology

テクノロジー

EXTJS のグリッドパネルにおける JSON データ利用

株式会社環
2010年1月8日 / 10:00
 
 
■はじめに
前回のコラムでは、EXTJSのグリッドパネルクラス導入編として、グリッドパネルクラスの紹介と、Ajaxを使ったサーバからのデータ取得までの説明をさせて頂きました。
今回から、グリッドパネルクラスの導入編と称して、前回までのサンプルを少しずつ改造していきながら、その他の機能をご紹介していきたいと思います。
今回も、Ajaxを使ったサンプルもご紹介したいと思います。サーバ側コードはPHP5.2.xで記載しておりますので、サンプルの動作をご確認される際には、同等程度の環境が必要となる点、ご了承ください。

■前回までのサンプルコード
さて、まずは前回までのサンプルコードを以下に示します。
今回のコラムの内容を読む前に、まずはこのコードで動作するところまでご確認ください。

―――――――――――――――HTMLコード―――――――――――――――
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>グリッドパネルクラスサンプル</title>
 
  <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css">
 
  <script type="text/javascript" src="extjs/adapter/ext/ext-base.js"></script>
  <script type="text/javascript" src="extjs/ext-all-debug.js"></script>
 
  <script type="text/javascript" src="src_8_1.js"></script>
 
  <script type="text/javascript">
    Ext.BLANK_IMAGE_URL = 'extjs/resources/images/default/s.gif';
   
    Ext.onReady( function()
    {
  var gridPanel = new Ext.ux.UserGridPanel( {
   applyTo:  'p'
  } );
 } );
  </script>
</head>

<body>

<br><br><br>
<div id="p" style="width: 600px; margin: 0 20em;">
</div>

</body>
</html>
――――――――――――――――――――――――――――――――

―――――――――――――――JavaScriptコード―――――――――――――――
Ext.namespace( 'Ext.ux.UserGridPanel' );
Ext.ux.UserGridPanel = Ext.extend( Ext.grid.GridPanel,
{
 
 title:            'グリッドパネルクラス-サンプル',
 width:            600,
 height:           300,
 stripeRows:       true,
 autoExpandColumn: 'birthday',
 loadMask:         {
  msg:     '読み込み中。しばらくお待ちください...'
 },
 columns:          [
  {id: 'userId',    header: 'ユーザID',     width: 70,  sortable: true, dataIndex: 'userId'},
  {id: 'userName1', header: 'ユーザ名(姓)', width: 160, sortable: true, dataIndex: 'userName1'},
  {id: 'userName2', header: 'ユーザ名(名)', width: 160, sortable: true, dataIndex: 'userName2'},
  {id: 'age',       header: '年齢',         width: 50,  sortable: true, dataIndex: 'age'},
  {id: 'birthday',  header: '誕生日',       width: 100, sortable: true, dataIndex: 'birthday', renderer: Ext.util.Format.dateRenderer('Y年m月d日')}
 ],
 
 
 /* このクラス用に独自に用意したプロパティ */
 dataFields:       [
  {name: 'userId',    type: 'string'},
  {name: 'userName1', type: 'string'},
  {name: 'userName2', type: 'string'},
  {name: 'age',       type: 'int'   },
  {name: 'birthday',  type: 'date',  dateFormat: 'Y-m-d'}
 ],
 
 
 //*****************************************************************
 //initComponentのオーバーライド
 //*****************************************************************
 initComponent: function()
 {
  
  //
  //storeクラスを構築
  //
  this.store = this.createStore();
  
  
  //
  //親クラスのinitComponentを呼び出す
  //
  Ext.ux.UserGridPanel.superclass.initComponent.call( this );
 },
 
 
 //*****************************************************************
 //Storeを構築するための独自メソッド
 //*****************************************************************
 createStore: function()
 {
  //
  //Ajaxでのリストデータ読み込み用のHTTPプロキシを構築
  //
  var proxy = new Ext.data.HttpProxy( {
   url    : 'http://www.example.com/src_8_1.php',
   method : 'POST'
  } );
  
  
  //
  //配列形式のデータを解釈するためのリーダの構築
  //
  var reader = new Ext.data.ArrayReader(
   {
    idIndex: 0,
   },
   this.dataFields
  );
  
  
  //
  //データストアの構築
  //
  return new Ext.data.Store( {
   autoLoad:   true,
   remoteSort: true,
   proxy:      proxy,
   reader:     reader
  } );
 }
} );
――――――――――――――――――――――――――――――――

―――――――――――――――サーバ側PHPコード―――――――――――――――
<?php

$testData = array(
 array( 'user01', '市山', '肇',     32, '1977-01-01' ),
 array( 'user02', '双葉', '次郎',   36, '1973-02-02' ),
 array( 'user03', '狭山', '光江',   49, '1960-03-03' ),
 array( 'user04', '司馬', '静子',   23, '1986-04-04' ),
 array( 'user05', '五味', '吾郎',   25, '1984-05-05' ),
 array( 'user06', '六場', '睦',     38, '1971-06-06' ),
 array( 'user07', '名鳥', '菜波',   23, '1986-07-07' ),
 array( 'user08', '八重', '靖男',   47, '1962-08-08' ),
 array( 'user09', '久喜', '熊次郎', 49, '1960-09-09' ),
 array( 'user10', '戸塚', '俊夫',   18, '1991-10-10' ),
 
 array( 'user11', '一場', '泉',     32, '1977-01-11' ),
 array( 'user12', '藤山', '房子',   36, '1973-02-12' ),
 array( 'user13', '三葉', '早苗',   49, '1960-03-13' ),
 array( 'user14', '滋賀', '芳之',   23, '1986-04-14' ),
 array( 'user15', '後藤', '逸美',   25, '1984-05-15' ),
 array( 'user16', '武藤', '六三郎', 38, '1971-06-16' ),
 array( 'user17', '名波', '直秀',   23, '1986-07-17' ),
 array( 'user18', '矢島', '弥生',   47, '1962-08-18' ),
 array( 'user19', '熊田', '久太郎', 49, '1960-09-19' ),
 array( 'user20', '豊橋', '利美',   18, '1991-10-20' )
);


sleep( 2 );
echo json_encode( $testData );
?>
――――――――――――――――――――――――――――――――

■JSON形式によるAjaxによる動的なデータ取得
前回コラムのAjaxサンプルは、Ext.data.ArrayReaderを使用して配列形式のデータを取得していました。
ただ、実際には、配列形式による受け取りよりデータベース上のフィールド名などがついたJSON形式(端的に言えば連想配列)の方を用いるケースが多いかと思います。
そこで、Ajaxサンプルを改造して、今度はJSON形式のデータとして取得するようにしてみたいと思います。

まず、JavaScript側のコードですが、先ほどのサンプルにおけるcreateStore()メソッド部分を以下のように変更します。

//*****************************************************************
//Storeを構築するための独自メソッド
//*****************************************************************
createStore: function()
{
//
//Ajaxでのリストデータ読み込み用のHTTPプロキシを構築
//
var proxy = new Ext.data.HttpProxy( {
url    : 'http://www.example.com/src_6_2.php',
        method : 'POST'
} );
   
   
//
//JSON形式のデータを解釈するためのリーダの構築
//
var reader = new Ext.data.JsonReader(
        {

idProperty:      'userId',
                      successProperty: 'success',

totalProperty:   'total',
root:            'data'
        },
        this.dataFields
);
   
   
//
//データストアの構築
//
return new Ext.data.Store( {
        autoLoad:   true,
        remoteSort: true,
        proxy:      proxy,
        reader:     reader
} );
}
 

今までのArrayReaderクラスからJsonReaderクラスへ変更します。また第一引数へのパラメータが変更となっています。
  idProperty  :レコード(行)データのidとして用いるカラムのキー名です。今回は「userId」
列をidとして用いています。
  successProperty :サーバ側でエラーが発生したかどうかの判定値を格納しているJSONデータ中の
キー名を設定します。
  totalProperty  :データのトータル件数が格納されているJSONデータ中のキー名を設定します。
  root   :実際に表示すべきデータがJSON形式データが格納されているキー名を設定しま
 す。

次にサーバ側のPHPコードを次のように変更します。

―――――――――――――――サーバ側PHPコード―――――――――――――――
<?php

$testData = array(
 array( 'userId' => 'user01', 'userName1' => '市山', 'userName2' => '肇',     'age' => 32, 'birthday' => '1977-01-01' ),
 array( 'userId' => 'user02', 'userName1' => '双葉', 'userName2' => '次郎',   'age' => 36, 'birthday' => '1973-02-02' ),
 array( 'userId' => 'user03', 'userName1' => '狭山', 'userName2' => '光江',   'age' => 49, 'birthday' => '1960-03-03' ),
 array( 'userId' => 'user04', 'userName1' => '司馬', 'userName2' => '静子',   'age' => 23, 'birthday' => '1986-04-04' ),
 array( 'userId' => 'user05', 'userName1' => '五味', 'userName2' => '吾郎',   'age' => 25, 'birthday' => '1984-05-05' ),
 array( 'userId' => 'user06', 'userName1' => '六場', 'userName2' => '睦',     'age' => 38, 'birthday' => '1971-06-06' ),
 array( 'userId' => 'user07', 'userName1' => '名鳥', 'userName2' => '菜波',   'age' => 23, 'birthday' => '1986-07-07' ),
 array( 'userId' => 'user08', 'userName1' => '八重', 'userName2' => '靖男',   'age' => 47, 'birthday' => '1962-08-08' ),
 array( 'userId' => 'user09', 'userName1' => '久喜', 'userName2' => '熊次郎', 'age' => 49, 'birthday' => '1960-09-09' ),
 array( 'userId' => 'user10', 'userName1' => '戸塚', 'userName2' => '俊夫',   'age' => 18, 'birthday' => '1991-10-10' ),
 
 array( 'userId' => 'user11', 'userName1' => '一場', 'userName2' => '泉',     'age' => 32, 'birthday' => '1977-01-11' ),
 array( 'userId' => 'user12', 'userName1' => '藤山', 'userName2' => '房子',   'age' => 36, 'birthday' => '1973-02-12' ),
 array( 'userId' => 'user13', 'userName1' => '三葉', 'userName2' => '早苗',   'age' => 49, 'birthday' => '1960-03-13' ),
 array( 'userId' => 'user14', 'userName1' => '滋賀', 'userName2' => '芳之',   'age' => 23, 'birthday' => '1986-04-14' ),
 array( 'userId' => 'user15', 'userName1' => '後藤', 'userName2' => '逸美',   'age' => 25, 'birthday' => '1984-05-15' ),
 array( 'userId' => 'user16', 'userName1' => '武藤', 'userName2' => '六三郎', 'age' => 38, 'birthday' => '1971-06-16' ),
 array( 'userId' => 'user17', 'userName1' => '名波', 'userName2' => '直秀',   'age' => 23, 'birthday' => '1986-07-17' ),
 array( 'userId' => 'user18', 'userName1' => '矢島', 'userName2' => '弥生',   'age' => 47, 'birthday' => '1962-08-18' ),
 array( 'userId' => 'user19', 'userName1' => '熊田', 'userName2' => '久太郎', 'age' => 49, 'birthday' => '1960-09-19' ),
 array( 'userId' => 'user20', 'userName1' => '豊橋', 'userName2' => '利美',   'age' => 18, 'birthday' => '1991-10-20' )
);


sleep( 2 );
echo json_encode( array(
 'success' => true,
 'total'   => count($testData),
 'data'    => $testData
)  );
?>
――――――――――――――――――――――――――――――――

各カラムは連想配列に変更し、キーを設定しています。キー値は、JavaScriptコード中の「dataFields」プロパティのnameパラメータと一致させてあります。

また、応答内容の返答ですが、連想配列にして「success」、「total」、「data」の各キーに対して各々の値を設定しています。こちらも先ほどのJavaScriptコード中でJsonReaderに対するパラメータと一致させています。

このように、サーバとJavaScript側との間でやり取りされるデータ形式が変わったとしても、比較的少ない手間で対応可能なことが分かって頂けるかと思います。

■行のダブルクリックによるイベントハンドラの追加
今度は、各行をクリックした際のイベントハンドラの登録を行っていきます。
イベントハンドラそのものの登録は、前回のコラムでご紹介した通りとなります。今回は、行をダブルクリックした際に発生する、「rodblwclick」イベントを利用します。

先ほどまでのサンプルのinitComponent()メソッドを以下のように修正します。

//*****************************************************************
//initComponentのオーバーライド
//*****************************************************************
initComponent: function()
{
//
//storeクラスを構築
//
this.store = this.createStore();
   
   
//
//rowdblclickイベントの登録

//
       this.on( 'rowdblclick', this.onRowDblClick, this );

   
   
//
//親クラスのinitComponentを呼び出す
//
Ext.ux.UserGridPanel.superclass.initComponent.call( this );
},
 


また、イベントハンドラとして以下のメソッドを追加します。

//*****************************************************************
//rowdblclickイベントのハンドラ
//*****************************************************************
onRowDblClick: function(grid, rowIndex, e)
{
var record = this.getStore().getAt( rowIndex );
   
var msg = String.format(
        'ダブルクリックしたのは"{0}({1} {2})"のレコードです。',
        record.get('userId'),
        record.get('userName1'),
        record.get('userName2')
);
   
alert( msg );
}

このイベントハンドラでは、クリックされた行のインデックスがハンドラ関数の引数に設定されていますので、そのインデックス値より、該当する場所のrecordオブジェクトを取得しています。
取得した、recordオブジェクト中のカラム値はget()メソッドにて取得できますので、その取得した値を元に文字列を生成し、alert()関数にてメッセージ表示しています。

グリッドパネル1
グリッドパネル1
*クリックして拡大

■Selectionの変更
今までのサンプルでは、複数の行が選択可能な状態でした(CTRLキーを押しながら、他の行をクリックする)。
このように、選択する動作を規定するために、Ext.grid.AbstractSelectionModelクラスが用意されています。
実際には、このクラス(実態は名称通り抽象クラスなので直接は使用できない)から派生された各種のクラスのインスタンス化したものを、グリッドパネルクラスの「selModel」パラメータに設定することで動作を変更できます。

グリッドパネル2
グリッドパネル2
*クリックして拡大

まずは、単一行のみ選択可能な状態にします。グリッドパネルクラスに以下のようにコードを追加します。

Ext.ux.UserGridPanel = Ext.extend( Ext.grid.GridPanel,
{
    selModel:         new Ext.grid.RowSelectionModel( {singleSelect: true} ), //→この行を追加
title:            'グリッドパネルクラス-サンプル',
width:            600,
   
  ・
  ・

これだけで、単一行選択になります。

もう一つ、CellSelectionModelを紹介します。こちらは各セル単位に選択ができるものです。こちらを利用する際にも、

Ext.ux.UserGridPanel = Ext.extend( Ext.grid.GridPanel,
{
    selModel:         new Ext.grid.CellSelectionModel(), //→この行を追加
title:            'グリッドパネルクラス-サンプル',
width:            600,
   
  ・
  ・


にて実現できます。

グリッドパネル3
グリッドパネル3
*クリックして拡大

■最後に
多少複雑だと思われるグリッドクラスにおける各機能を、いくつかご紹介させて頂きました。
グリッドパネルクラスでは、複数のクラスを利用する必要があるため、最初は難しく感じるかもしれません。ただ一つ一つのクラスは比較的単純な構成ですので、分からないことはマニュアルなどで丹念に調べて頂ければきっとご理解していただけるのではないかと思います。
実際に、サイトに適用するには、ページングなどの機能が必要となるかと思います。EXTJSの中には豊富なサンプルコードがあり、ページングを使ったものもありますので、そちらのほうも参考にしてみてください。

記事提供:株式会社環
【関連記事】
EXTJS のグリッドパネルを使ってみる
EXTJS のツリーパネルにおける Ajax 利用
EXTJS で用意されているウィジェット利用(ツリーパネル−導入編)
EXTJS で用意されているウィジェット利用(タブパネル編)
環、アクセス解析ツール「シビラ」に「ドメイン・組織名分析」を追加。

New Topics

Special Ad

ウマいもの情報てんこ盛り「えん食べ」
ウマいもの情報てんこ盛り「えん食べ」 「えん食べ」は、エンジョイして食べる、エンターテイメントとして食べものを楽しむための、ニュース、コラム、レシピ、動画などを提供します。 てんこ盛りをエンジョイするのは こちらから

Hot Topics

IT Job

Interviews / Specials

Popular

Access Ranking

Partner Sites