« ニューiMac | トップページ | 親指と日本語とゲームの話 »

2009年10月25日 (日)

いよいよjqGrid使ってみる

 jqGridは、JavaScriptライブラリであるjQueryのプラグインで、リッチな感じのテーブルだ。見た目、結構かっこ良さ気なんだよね。Excelっぽくて。

 こいつを使って、DBを検索した結果を表示してみようと思った。

■参照したサイト

  • jQuery本家
    JavaScriptライブラリjQueryや、jQueryベースのテーマフレームワークjQuery UIを、ダウンロードできたりマニュアル読めたり。ただし全部英語。
  • jQuery日本語リファレンス
    jQueryの日本語リファレンスのサイト。本家の英語の翻訳に疲れたときに利用。お世話になってます。
  • jqGrid配布元
    jQueryプラグインのjqGridのダウンロードとか最新版のリリース情報とか。英語サイト。
  • jqGrid Wiki
    jqGridの使い方とかリファレンスとか。インストールや最初の一歩的簡単な使い方から書かれてる。英語サイト。
  • jqGridのデモ
    jqGridのデモページ。各機能毎にデモを見れる。

■ファイルの配置

 最初jQueryを使い始めた頃、どのファイルをどう配置していいのかよくわかんなかったんだが、使ってみるとあんまりそこは気にしなくてもいいという気がしてくる。ちゃんとjQueryを使うページからリンクするように正しくパスが書かれていれさえすれば。

 ただダウンロードしてきたファイル名にバージョン番号が含まれていることがあって、バージョンアップしてファイル名が変わってしまったときの手間を考えてバージョン番号を含まない名前にリネームする気遣いくらいはした。

 一応今回自分が配置した様子はこんな感じ。あくまでも一例ってことで。

+ インストールディレクトリ
index.php (メイン画面 自作)
search.php (Ajax返答用 自作)
+ js
   jquery.js (jquery-1.3.2.min.jsをリネーム)
   jquery-ui.js (jquery-ui-1.7.2.custom.min.jsをリネーム)
   jquery.jqgrid.js (jquery.jqGrid.min.jsをリネーム)
   + i18n (jqGridに同梱されているディレクトリ)
+ css
   ui.jqgrid.css (jqGridに同梱)
   + ui-lightness (jQuery UIに同梱 テーマによって名前変わる?)
     jquery-ui.css (jquery-ui-1.7.2.custom.cssをリネーム)

■メイン画面のヘッダ(1)

 JavascriptファイルやらCSSファイルやらを指定しておかなくては。

 jqGridはjQueryのプラグインなので、当然jqGridのファイルと一緒にjQueryのファイルも必要となる。さらにjqGridの見た目はjQuery UIに制御されているようなので、それも指定しておく必要がある。

 その辺、実はjqGrid Wikiの中に「My First Grid」というページがあって、例が示されていた。

<link rel="stylesheet" href="./css/ui-lightness/jquery-ui.css"
    type="text/css" />
<link rel="stylesheet" href="./css/ui.jqgrid.css" type="text/css" />

<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript" src="./js/i18n/grid.locale-jp.js">
</script>
<script type="text/javascript" src="./js/jquery.jqgrid.js">
</script>

 もう一つ、jqGridの本体についての記述が必要になる。次のような感じで書いてみた。

<script type="text/javascript">
$(document).ready(function(){
//jqGrid初期化
$("#list").jqGrid({
  url:'search.php',
  datatype: 'json',
  mtype: 'POST',
  colNames:[
    'id','クリスタル','アイテム名', 'ランク',
    'スキル','限界','素材','説明'
  ],
  colModel :[
   {name:'item_id', index:'item_id', width:1, hidden:true},
   {name:'crystal_name', index:'crystal_name',
                              width:90, align:'center'},
   {name:'item_name', index:'item_name', width:80, align:'center'},
   {name:'rank_name', index:'rank_name', width:80, align:'center'},
   {name:'skill_name', index:'skill_name', width:80, align:'center'},
   {name:'skill_cap', index:'skill_cap', width:80, align:'center'},
   {name:'material_item', index:'material_item',
                              width:80, align:'left'},
   {name:'item_text', index:'item_text', width:80, align:'left'}
  ],
  rowNum:10,
  sortname: 'skill_cap',
  sortorder: 'asc',
  caption: '検索結果'
});
});
</script>

 まず基本的に、jQueryのコードはページが読み込まれたとき(正確にはDocumentがReadyになったとき?)に実行するものらしい。なので、HTMLファイルのヘッダ部に、

<script type="text/javascript">
$(document).ready(function(){
  // ここに任意のコード
});
</script>

 と書くのがお決まりらしい。今回のも実際に中にはjqGridの記述をしてある。

 さてそのjqGrid。まず基本は、

$("#list").jqGrid({ /* ここにいろいろ初期値を書く */ });

 と書く。冒頭の「#list」は、「id="list"と書かれているタグ」を意味している。こう書くと、id="list"と書かれているタグにjqGridの表が描かれる。

 中身はというと、jqGridに関するオプションがいろいろ書いてある。

 urlは相手のurl。特に今回作ろうとしているもので言うと、このurlに対して画面上で指定された検索条件を送信して、このurlに示す相手が検索結果を送り返してきてくれる。

 datatypeはurlで指定した相手がどういう形式でデータを返すのか。今回はjsonを指定してある。もちろん相手が最後にjson形式で送信するようにコーディングされていなければならない。

 mtypeはurlで指定した相手がどのメソッドでデータを受け取るか。言い換えると、jqGrid側がデータをどう送るか。postかgetかで言う。

 colNamesとcolModelは、jqGridで表示する表の列の定義だな。colNamesが実際に表示される列名になる。colModelの方は俺もあまりよく理解していない。特にindexとnameがどう違うのか・・・。実際サーバ側から検索結果データを送りつけるときもこの名前を使っているわけでもないし・・・。

■ボディ部

 jqGridに関するボディ部の記述は至って簡単。

<table id="list"></table>

 この1行だけでいい。tableタグだけ書いて、中身はいらない。jqGridが勝手に動的に書いてくれるから。

 それと、検索条件を指定するためのformを書いておかなければ。

<form>
名前 <input size="60" type="text" id="item_name" />
<input type="button" value="&nbsp;検索&nbsp;" id="btnSearch" />
<input type="reset" value="クリア" id="btnClear" /><br />
スキル <select id="skill_name"><?php skill_option(); ?></select> 
ランク <select id="rank_name"><?php rank_option(); ?></select> 
クリスタル <select id="crystal_name">
<?php crystal_option(); ?></select>
<label for="cbxText">
<input type="checkbox" id="cbxIncludeMaterial" />素材も含む
</label>
</form>

 このformで直接データをpostやgetで送るわけではないので、formタグにはactionとかmethodとかは書いてないし、type="submit"なボタンも用意していない。

 ちなみにselectタグで囲まれてるphpの部分は、optionタグを書くもの。中身はDBから読んできてるが、実際のところはそうそう変化する値ではないので直書きでも良かったな。

■検索ボタンで検索したい

 ここまでで、とりあえず画面には検索条件を入力するためのフォームとjqGridのテーブルは表示される。でも、検索に関するコードは一切書いてないのでどこをどうしてもウンともスンとも言わない。

 ここから、その検索のコードを書き加える。

 jqGrid自体はヘッダ部で書いたオプションに従って画面がロードされた時に一回だけサーバ側と通信するが、後はそれっきりだったりする。実はjqGridにはpostDataというオプションがあって、指定しておくとサーバ側と通信するときにpostDataで指定したデータを送ってくれるんだが、何にもしなければそのデータも画面がロードされた時に一回だけしか送ってくれない。

 でもやりたいことは、画面がロードされた後にページを使う人がform内の検索条件を指定して検索ボタンをクリックしたときに検索をさせたいってことだ。

 それをするために(だよなきっと)、jqGridにはsetGridParam()というメソッドと、trigger("reloadGrid")というメソッドが装備されている。

 検索ボタンをクリックしたときの動作として、その時点の検索条件をsetGridParam()を使ってpostDataに突っ込んでおいて、即座にtrigger("reloadGrid")してあげれば、望んでいる動作をしてくれる。

■メイン画面のヘッダ(2)

 先ほど書いたヘッダ部のJavaScriptに少し書き加える。

<script type="text/javascript">
$(document).ready(function(){
//jqGrid初期化
$("#list").jqGrid({
  // 前述と同じなので省略
});
//検索ボタンのOnClickイベントハンドラ(追加部分)
$("#btnSearch").click(function(){
  $("#list").setGridParam({
   postData : {
    item_name        : $("#item_name").val(),
    skill_id         : $("#skill_name option:selected").val(),
    rank_id          : $("#rank_name option:selected").val(),
    crystal_id       : $("#crystal_name option:selected").val(),
    include_material :
     ($("#cbxIncludeMaterial").val()=='on')?true:false
   }
  });
  $("#list").trigger("reloadGrid");
});
});
</script>

 こう書いておくと、検索ボタンをクリックしたときに最初のjqGridのオプションで書いたurlで指定されるサーバ側のファイルへpostDataの値が送られる。

■サーバ側スクリプト

 jqGridのオプションurlで指定されたファイルの方はというと、postデータが渡されるのでそれを元にDB検索して結果をjson形式で表示するスクリプトを組むことになる。

 俺が作ったphpのスクリプトは、こう。

//ほしいpostデータが無ければ即終了
if(!array_key_exists('item_name',$_POST)) return;

//postデータの保存
$item_name = $_POST['item_name'];
$skill_id = $_POST['skill_id'];
$rank_id = $_POST['rank_id'];
$crystal_id = $_POST['crystal_id'];
$include_material = $_POST['include_material'];

//DB検索
$pdo = new db_pdo();
$result =
$pdo->SearchRecipe($item_name,$skill_id,$rank_id,$crystal_id);

//検索結果返却用配列作成
$rtn = array();
for($i=0;$i<count($result);$i++){
$rec = $result[$i];
$rtnrec['id'] = $rec['item_id'];
$rtnrec['cell'] =
  array($rec['item_id'],$rec['crystal_name'],$rec['item_name'],
        $rec['rank_name'],$rec['skill_name'],
        $rec['skillcap'.($rec['skill_id']+1)],
        $rec['item1_name'].'<br />'.$rec['item2_name'].'<br />'.
        $rec['item3_name'].'<br />'.$rec['item4_name'].'<br />'.
        $rec['item5_name'].'<br />'.$rec['item6_name'].'<br />'.
        $rec['item7_name'].'<br />'.$rec['item8_name'],
        $rec['item_text']);
  $rtnrec = convert_utf8($rtnrec);
  $rtn[] = $rtnrec;
}
$responce->page = 1;
$responce->total = 1;
$responce->records = count($rtnrec);
$responce->rows = $rtn;

echo json_encode($responce);

 json_encode()する対象の配列$responceの作り方は、jqGridのサイトに掲載されていたものをほぼそのままパクった。正直理解し切れていない。ただ['cell']で示される要素の中に、実際表示するデータをぱらぱらと並べている。

 検索ボタンがクリックされたときには検索条件がpostされてくるが、画面ロード時の最初の一回はそのデータが無いはずなので、その考慮もしておいた。

 あと、上記のDB検索時のdb_pdoクラスは自作のもの。抜粋は以下。

public function SearchRecipe($item_name,$skill_id,
                      $rank_id,$crystal_id)
{
//item_nameのwhere句
$item_name = preg_replace('/^\*|\*$/','%',trim($item_name));
if(strlen($item_name)==0) $item_name = '%';
$item_name = mb_convert_encoding($item_name,'UTF-8','AUTO');
//skill_idのwhere句
if($skill_id >= 0)
$where_skill_id = 'recipe.skill_id = '.$skill_id.' and ';
else $wherre_skill_id = '';
//rank_idのwhere句
if($rank_id >= 0)
$where_rank_id = 'recipe.rank_id = '.$rank_id.' and ';
else $wherre_rank_id = '';
//crystal_idのwhere句
if($crystal_id >= 0)
$where_crystal_id = 'recipe.crystal_id = '.$crystal_id.' and ';
else $where_crystal_id = '';
//SQL文生成
$sql = <<< SQLEND
select
recipe.item_id, crystal.crystal_name, item.item_name,
rank.rank_name, skill.skill_name, recipe.skill_id,
recipe.skillcap1, recipe.skillcap2, recipe.skillcap3,
recipe.skillcap4, recipe.skillcap5, recipe.skillcap6,
recipe.skillcap7, recipe.skillcap8, recipe.skillcap9,
item1.item_name as item1_name, item2.item_name as item2_name,
item3.item_name as item3_name, item4.item_name as item4_name,
item5.item_name as item5_name, item6.item_name as item6_name,
item7.item_name as item7_name, item8.item_name as item8_name,
item.item_text
from
  crystal, item, rank, recipe, skill,
  item item1, item item2, item item3, item item4,
  item item5, item item6, item item7, item item8
where
  recipe.item_id = item.item_id and
  recipe.material_item_id1 = item1.item_id and
  recipe.material_item_id2 = item2.item_id and
  recipe.material_item_id3 = item3.item_id and
  recipe.material_item_id4 = item4.item_id and
  recipe.material_item_id5 = item5.item_id and
  recipe.material_item_id6 = item6.item_id and
  recipe.material_item_id7 = item7.item_id and
  recipe.material_item_id8 = item8.item_id and
  recipe.skill_id = skill.skill_id and
  recipe.rank_id = rank.rank_id and
  recipe.crystal_id = crystal.crystal_id and
  {$where_skill_id}
  {$where_rank_id}
  {$where_crystal_id}
  item.item_name like '{$item_name}'
SQLEND;
return $this->execute_sql($sql);
}

public function execute_sql($sql)
{/* 汎用SQL実行・結果はfetchAll()
*/
$sth = $this->PDO->prepare($sql);
$sth->execute();
$rtn = $sth->fetchAll(PDO::FETCH_ASSOC);
return $rtn;
}

 これで検索してみた結果は、こんな感じ。

200910241

 ふぅ~・・・なげぇ(ーoー)y゜゜  しかも俺が書いたSQL文に間違いがあるらしく、検索結果が予定より少ない・・・この後もうちっと書き換え必要だな。素材を含むオプション実装してないし。

« ニューiMac | トップページ | 親指と日本語とゲームの話 »

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/95697/31929558

この記事へのトラックバック一覧です: いよいよjqGrid使ってみる:

« ニューiMac | トップページ | 親指と日本語とゲームの話 »

2010年11月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30