jsTreeはツリーを生成するjQueryのプラグインで、HTMLかXMLかJSONフォーマットのデータを読み込ます前提ですが、業務システムでDBのテーブルにある部品構成(BOM)や部門構成等をツリーで表示する場合には、HTMLリストを動的に生成してツリーに変換させます。
このHTMLリストを動的に生成する際に必要なのが再帰処理(Recursive processing)であり、昔々の情報処理試験アルゴリズム対策のためには必須事項だったのですが、同期の新入社員の間でも一番難しい類の内容だったように記憶しています。
HTMLリストの構造
HTMLリストは<ul>で開始してリストの各アイテムを<li>と</li>で囲んで列挙し</ul>で終了します。当然以下のように入れ子に出来ますので、再帰処理でDBのテーブルから動的に入れ子のHTMLリストを生成することになります。
1 2 3 4 5 6 7 8 9 |
<ul> <li>node1_1 <ul> <li>node2_1</li> <li>node2_2</li> </ul> </li> <li>node1_2</li> </ul> |
このHTMLリストをjsTreeでツリー表示するには、HTMLリストをdiv要素のidセレクタ指定で囲み、jQuery関数からidセレクタでHTMLリストを探して、jstreeメソッドでツリー表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//HTMLリストをdiv要素で囲む <div id="html"> <ul> <li>node1_1 <ul> <li>node2_1</li> <li>node2_2</li> </ul> </li> <li>node1_2</li> </ul> </div> // idセレクタでHTMLリストを取得しjstreeメソッドでツリー表示 $('#html').jstree({ |
で、今回やろうとしていることは以下のような部品構成の親子関係をHTMLリストに生成してjsTreeメソッドでツリー表示することです。
上記のテーブルの親子関係からこんな感じでツリー表示します。
jQueryとjsTreeの呼び出し
Headタグ内にjsTreeのテーマテンプレートとjQuery関数とjsTreeプラグインの3つを読み込み、
1 2 3 4 5 |
<head> <link rel="stylesheet" href="themes/default/style.min.css" /> <script src="jquery.js"></script> <script src="jstree.min.js"></script> </head> |
ツリーのソース用DB(BOMの親子関係を定義するテーブル)のパラメータ定義。
1 2 3 4 5 |
$host = "localhost"; $user = "root"; $password = "password"; $db = "asp"; $table = "asp_integrated"; |
HTMLリストをdiv要素のidセレクタ(html)で囲み、ツリーの根っこ部分をRootとして定義。
1 2 3 4 |
<div id="html"> <ul> <li>Root <ul> |
再帰処理関数による親子レコード取得とツリー実装の流れ
以上が前準備で、ここから処理が始まります。
1.子品目データが存在すればマッチする親品目のレコードセットを配列$mainに格納。
2.子品目データが存在しなければそのまま親品目のレコードセットを配列$mainに格納。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$con = mysql_connect($host, $user, $password); $db_selected = mysql_select_db($db, $con); $sql = "SELECT C_ITM_CD from $table"; $result = mysql_query($sql); if(isset($_GET['node']) and $_GET['node']<>""){ $sql = "select P_ITM_CD from $table where P_ITM_CD='".$_GET['node']."'"; }else{ $sql = "select P_ITM_CD from $table"; } $result = mysql_query($sql); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { $main[] = $row["P_ITM_CD"]; } |
配列$mainから要素(親品目のレコード)を1個ずつ取り出して再帰処理関数getChild()に渡す。
1 2 3 4 5 6 7 8 9 |
if(isset($main)){ foreach($main as $main_item){ echo "<li>".$main_item; echo getChild($con, $main_item, $table)."</li>\n"; } } mysql_close($con); |
この再帰処理関数が難しいのですがポイントです。
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 |
function getChild($con, $item, $table){ $sql = "select * from $table where P_ITM_CD='".$item."'"; $result = mysql_query($sql, $con); $num_rows = mysql_num_rows($result); if($num_rows > 0){ //子品目ありの場合 unset($sem); while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) { if($row["C_ITM_CD"] != ""){ $sem[] = $row["C_ITM_CD"]; } } $str = ""; foreach($sem as $sem_item){ $child = getChild($con, $sem_item, $table); if( $child == ""){ $str .= "<ul><li>".$sem_item."</li></ul>\n"; }else{ $str .= "<ul><li>".$sem_item."$child</li></ul>\n"; } } return $str; }else{ //子品目なしの場合 } } |
上記までで生成した再帰HTMLリストをツリービューで表示します。まずjstreeメソッドでツリー表示のインスタンスを生成する部分ですが、基本JavaScriptですので<script>タグ内に記述します。
jstreeメソッドのオプションとしてcoreとdndとpluginsの3つを指定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<script> //jstreeメソッドでツリービューのインスタンス作成 $('#html') .jstree({ "core" : { 'check_callback' : function (operation, node, node_parent, node_position, more) { node_dest = node_parent["text"].replace(regex, "").trim(); var res = node_dest.split("["); if(res[0] == "Root"){ return false; node_dest = ""; }else{ node_dest = res[0]; return true; } } }, "dnd" : { }, "plugins" : [ "themes", "html_data", "dnd" ] }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function uiGetParents(loSelectedNode) { try { var lnLevel = loSelectedNode.node.parents.length; var lsSelectedID = loSelectedNode.node.id; var loParent = $("#" + lsSelectedID); var lsParents = loSelectedNode.node.text + ' >'; for (var ln = 0; ln <= lnLevel -1 ; ln++) { var loParent = loParent.parent().parent(); if (loParent.children()[1] != undefined) { lsParents += loParent.children()[1].text + " > "; } } if (lsParents.length > 0) { lsParents = lsParents.substring(0, lsParents.length - 1); } str_parent = lsParents.replace(/(<([^>]+)>)/ig,""); } catch (err) { alert('Error in uiGetParents'); } } </script> |