TreeView Control: Dynamically Loading Node Data
Default Treviewの次にしては、この「Dynamically Loading Node Data」は、タフなサンプル。
タイトル通り、データをダイナミックにロードしながらNodeを作成し、Treeを構築する(トップ画面の表示を早くする、という目的のため)。
サンプルでは、YAHOO!のRelated Suggestion APIというWebサービスを利用し(Related Suggestion APIの仕様はこちら)、トップノードについてのSuggestを探索して、子ノードを追加していく。
YUIに掲載されているサンプルは「インドの州の名前」という馴染みのないものなので、サンプリングで作成したスクリプトでは、Ajaxに関連するワードに変更した。
また、YUIのサンプルはConnection Managerを使って、自サーバー(YUIのExampleを表示するサーバー)上のPHPプログラムをProxyにしている。
これは中身が分からないので、Get.scriptをつかって、スクリプト内から直接、APIを呼ぶようにした。(以前にやった、Get.scriptのサンプリングについては、こちらか、こちらを参照)
初期画面は以下。
画面上にExpand/CollapseとLeafという選択があるが、これらは
Expand/Collapse | ノードに子要素が見つからなくてもノードに「±」マークをつける |
Leaf | ノードに子要素が見つからない場合には「±」マークをつけない |
の違いだけである。
下の画面(上)がExpand/Collapseの場合、(下)がLeafの場合である。Leafの場合、WebServiceで「子ノードがないこと」を確認するため、表示が確定するまでに若干、時間がかかる。
また、トップノートの最後に「This is a Leaf Node」というノードがあるが、これは、ノードのisLeafプロパティーをtrueに設定した場合のサンプルである。
以下にJavaScriptを含む、HTMLの全文を示す。
<HTML> <HEAD> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <TITLE>Ajax_Sampling</TITLE> <style type="text/css"> body { margin:0; padding:0; } </style> <link rel="stylesheet" type="text/css" href="scripts/yui/fonts/fonts-min.css" /> <link rel="stylesheet" type="text/css" href="scripts/yui/treeview/assets/skins/sam/treeview.css" /> <style type="text/css" id="defaultstyle"> #container { margin: 2px; padding: 3px; width: 350px; height: auto; border:1px dashed #999999; } #treeDiv1 { background: #fff; padding:1em; } </style> <!-- 読み込むjs --> <script type="text/javascript" src="scripts/yui/yahoo-dom-event/yahoo-dom-event.js" ></script> <script type="text/javascript" src="scripts/yui/treeview/treeview-min.js" ></script> <script type="text/javascript" src="scripts/yui/utilities/utilities.js" ></script> <script type="text/javascript"> //alert("init"); //モジュールパターンで実装する。 YAHOO.namespace("EGP"); //YAHOO! Suggetstから、GetScriptで書いてみる。 //module patternで書くことにする。 YAHOO.EGP.SuggetstPicker = function() { var Event = YAHOO.util.Event, Get = YAHOO.util.Get, tree, currentIconMode, wkNode; var onSuggetstPickerSuccess = function(o) { o.data.loadComplete(); }; var onSuggetstPickerFailure = function(o) { o.data.loadComplete(); }; var loadNodeData = function(node, fnLoadComplete) { // callback用にいったん関数外に出す。 wkNode = node; // YAHOO! Suggest APIを利用するURLを準備する。 // outputはjson、リターンのリストは10個(default)を指定する。 var sURL = "http://search.yahooapis.com/WebSearchService/V1/relatedSuggestion" + "?appid=YahooDemo&output=json&results=10" + "&callback=YAHOO.EGP.SuggetstPicker.callback" + "&query=" + encodeURIComponent(node.label); // Get Utilityを使い、Web Serviceからデータを取得するcallbak定義。 var transactionObj = Get.script(sURL, { onSuccess: onSuggetstPickerSuccess, onFailure: onSuggetstPickerFailure, data : node, scope : this }); }; // Expand/Collapse、Leaf選択時のイベントハンドラ var changeIconMode = function () { var newVal = parseInt(this.value); if (newVal != currentIconMode) { currentIconMode = newVal; } buildTree(); }; var buildTree = function () { //Treeのインスタンス化: tree = new YAHOO.widget.TreeView("treeDiv1"); //Treeにダイナミックなノードロードを行うことを指定する。 tree.setDynamicLoad(loadNodeData, currentIconMode); //最上位の指定 var root = tree.getRoot(); // Topレベルのノードの定義 var aStates = ["javascript","ajax","yui","jquery","extjs", "prototype.js","dojo","script.acuio.us","mootools" ]; // i,jの定義(初期値設定)と、終末条件、インクリメントを同時に指定している。 for (var i=0, j=aStates.length; i<j; i++) { var tempNode = new YAHOO.widget.TextNode(aStates[i], root, false); } // isLeafプロパティーをtrueにするデモ用のノード。 // isLeaf=trueとすると、そのノードはダイナミックロードできなくなる。 // Expand/Collapseモードだと子要素がなくても「-」がでるが、それもでない。 var tempNode = new YAHOO.widget.TextNode('This is a leaf node', root, false); tempNode.isLeaf = true; // Treeの描画 tree.draw(); }; // まず、無名関数を定義する。 return { // DOMReadyで最初に呼ばれる初期化関数。 init: function() { YAHOO.util.Event.on( ["mode0", "mode1"], "click", changeIconMode ); var el = document.getElementById("mode1"); if (el && el.checked) { currentIconMode = parseInt(el.value); } else { currentIconMode = 0; } buildTree(); }, // WebServiseのコールバック関数。 // (??) Get utilityの場合、レスポンスからのresultのとり方がわからない。 // 以下のようにして、YAHOO Web ServiceのCallbackを使えば取れる。 callback: function(results) { if((results.ResultSet.Result) && (results.ResultSet.Result.length)) { // 取得できた場合、結果は配列か、String。 if(YAHOO.lang.isArray(results.ResultSet.Result)) { // 配列の場合の処理 for (var i=0, j=results.ResultSet.Result.length; i<j; i++) { var tempNode = new YAHOO.widget.TextNode(results.ResultSet.Result[i], wkNode, false); } } else { //Stringの時の処理 var tempNode = new YAHOO.widget.TextNode(results.ResultSet.Result, wkNode, false) } } // 子要素の作成が終わったら、nodeのloadConplete()コールバックメソッド // を呼んで、load完了を通知する。 wkNode.loadComplete(); // 関数外に保管していたnodeをクリアする。 wkNode=null; } }; }(); YAHOO.util.Event.onDOMReady( YAHOO.EGP.SuggetstPicker.init, YAHOO.EGP.SuggetstPicker, true ); </script> </HEAD> <!-- class=" yui-skin-sam"の指定が必要 --> <BODY class=" yui-skin-sam"> <div id="container"> <p> <h4><a href="http://developer.yahoo.com/search/web/V1/relatedSuggestion.html"> Yahoo! Suggest API</a>からノードを動的に生成します。</h4> Expand/Collapseモードでは、子要素が見つからなくても(-)が表示されますが、Leadモード では、子要素が見つからない場合、表示されません。<br/> 「This is a leaf node」は、nodeを強制的にleafにした場合のデモです。 </p> <h3>Childless Node Style:</h3> <dd><label for="mode0"> <input type="radio" id="mode0" name="mode" value ="0" checked /> Expand/Collapse</label> </dd> <dd><label for="mode1"> <input type="radio" id="mode1" name="mode" value ="1" /> Leaf Node</label> </dd> <div id="treeDiv1"></div> </div> </BODY> </HTML>