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>