JsonreststoreとJsonpが搭載した怠zyなロードDojo Tree
-
28-10-2019 - |
質問
Dojo Toolkitを使用して、クロスドメイン、怠zyなロードツリーを実装しようとしています。これまでのところ、トップレベルのノードが正しく表示されていますが、Expandoをクリックすると、「延期されている」エラーが発生しましたが、その理由はわかりません。 FireBugネットワークタブを見ることで、Fetchメソッドが機能しているように見えることがわかります。私の問題は私の_processResultsメソッド内にあると思います。おそらく、その中の_loadObjectの定義と関係があります...
私はそれを理解しようとしている間ずっと、Dojoをよりよく知っているべきだと思います。しかし、悲しいかな、それはかなりの獣です...私はJSONPと怠zyloadingについての言及を見てきました。http://www.sitepen.com/blog/2008/06/25/web-service-data-store/ )、しかし、JsonpがAsyncronusである以外に不可能であるべきではない理由は言及していません。 DojoがJSONのデータを入っているだけで店に詰め込むだけなら、なぜそれが重要なのかわかりません。
おそらく、それは私のデータのフォーミングに関係しています - Sitepenの別の例(http://www.sitepen.com/blog/2010/01/27/efficient-lazy-loading-of-a-tree/)JSONRESTSTOREを使用すると、ノードを展開するまでアイテムをロードしませんが、私のフォーマットはアイテムをロードしますが、展開するまで子供ノードをロードしません...
これ以上苦労せずに、ここにTA CODEZがあります...
<script type="text/javascript">
dojoConfig = {
parseOnLoad: true,
isDebug: true,
usePlainJson: true
};
</script>
<script type="text/javascript" src="scripts/dojo_16/dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("dojo.io.script");
dojo.require("dojox.rpc.Service");
dojo.require("dojox.data.ServiceStore");
dojo.require("dijit.tree.ForestStoreModel");
dojo.require("dijit.Tree");
dojo.addOnLoad(function(){
var mySmd = {
"SMDVersion": "2.0",
"id": "http://urlbehindfirewall/testtree/",
"description": "This is the service to get to the finder app backend data",
transport: "JSONP",
envelope: "URL",
additionalParameters: true,
target: "http://urlbehindfirewall/testtree/",
services: {
"getChildrenNodes": {
"target": "getChildrenNodes.php",
parameters: [
{ name: "nodeId", type: "integer"}
]
}
}
};
var myService = new dojox.rpc.Service(mySmd);
var myStoreParams = {
service : myService.getChildrenNodes,
idAttribute : "Node_Id",
labelAttribute : "Display_Name",
_processResults: function(results, def){
var _thisStore = this;
for(i in results){
results[i]._loadObject = function(callback){
_thisStore.fetch({
query: { nodeId: this.Node_Id },
onItem: callback
});
delete this._loadObject;
};
}
return {totalCount: results.length, items: results};
}
};
var myStore = new dojox.data.ServiceStore(myStoreParams);
//create forestTreeModel
var treeModelParams = {
store: myStore,
deferItemLoadingUntilExpand: true,
childrenAttrs: ["Children_Nodes"],
rootId : 1,
query: 1
};
var treeModel = new dijit.tree.ForestStoreModel(treeModelParams);
var myTree = new dijit.Tree({
model: treeModel,
id: "myTree",
showRoot: false
});
dojo.byId("treeContainer").appendChild(myTree.domNode);
myTree.startup();
});
</script>
そして、JSONデータ構造の例を次に示します。残念ながら、サービスは現在ネットワークファイアウォールの背後にあります...私はパブリックバージョンを設置して少しでデモンストを掲載します。一方、これはルートノード、ノード1で検索するための応答です。
[
{
"Node_Id":"2",
"Display_Name":"LeftNode:2",
"Secondary_Names":"Parent:1",
"Obi_Id":"10002",
"Children_Nodes":[
],
"Has_Children":true,
"Child_Node_Ids":[
"5",
"6",
"7",
"8"
]
},
{
"Node_Id":"3",
"Display_Name":"Middle Node:3",
"Secondary_Names":"Parent:1",
"Obi_Id":"10003",
"Children_Nodes":[
],
"Has_Children":true,
"Child_Node_Ids":[
"9",
"10"
]
},
{
"Node_Id":"4",
"Display_Name":"Right Node:4",
"Secondary_Names":"Parent:1",
"Obi_Id":"10004",
"Children_Nodes":[
],
"Has_Children":true,
"Child_Node_Ids":[
"11",
"12"
]
}
]
上記のノードのいずれかを拡張すると、そのノードの子供が得られます。そのため、2は5,6,7,8のノード配列を取得します。 (現在の実装のためにchild_node_idsとchildren_nodesを持つ必要はないかもしれませんが、何も壊すべきではありませんか?)
それで、問題を言い換えるために、目がglazingしていると確信しています - この「延期されたものがすでに解決されている」エラーを作成しているのは何ですか? jsonpで木に怠zyなロードが可能ですか?別のJSON構造が私の怠zyなロードの問題を解決しますか? Dojo内のデータを再フォーマットして機能するようにすることは可能ですか? (それが_ProcessResultsメソッドのポイントだと思いました...)練習する公開可能なツリーデータサービスはありますか?
みんな、ありがとう!
解決
多くの実験と欲求不満の後、これらは私の発見です:
はい、JSONPを使用してツリーの怠zyなロードが可能です。はい、私のデータを別の形式に配置すると、怠zyなロードの問題の解決に役立ちました。私は途中で多くのつまずきのブロックを見つけましたが、それについては後で言及します。
実用化のコードは次のとおりです。最初にサービス:
pretendservice.php
$callback = $_GET["callback"];
$nodeName = $_GET["node"];
$fileName = "pretendServiceJson/".$nodeName.".js";
print($callback . "(" . file_get_contents($fileName) . ")" );
?>
pretendservicejson/0.js - これは初期データロードノートです それは配列です!
[
{
"Node_Id":"0",
"Display_Name":"",
"Children":[
{
"Node_Id":"1",
"Display_Name":"node 1",
"Obi_Id":"02",
"Secondary_Names":"Blah blah secondary name node 1"
},
{
"Node_Id":"2",
"Display_Name":"node 2",
"Obi_Id":"o2",
"Secondary_Names":"Blah blah secondary name node 2"
},
{
"$ref":"3",
"Display_Name":"node 3",
"Obi_Id":"o3",
"Secondary_Names":"Blah blah secondary name node 3",
"Children":true
},
{
"Node_Id":"4",
"Display_Name":"node 4",
"Obi_Id":"o4",
"Secondary_Names":"Blah blah secondary name node 4"
},
{
"Node_Id":"5",
"Display_Name":"node 5",
"Obi_Id":"o5",
"Secondary_Names":"Blah blah secondary name node 5"
}
]
}
]
pretendservicejson/3.js - これは最初の怠zyなロードされたアイテムになります - 注 それはオブジェクトです!!!
{
"Node_Id": "3",
"Display_Name": "node 3",
"Obi_Id": "o3",
"Secondary_Names": "Blah blah secondary name node 3",
"Children": [
{
"$ref": "6",
"Display_Name": "node 6",
"Obi_Id": "o6",
"Secondary_Names": "Blah blah secondary name 06",
"Children":true
},
{
"Node_Id": "7",
"Display_Name": "node 7",
"Obi_Id": "o7",
"Secondary_Names": "Blah blah secondary name 07"
}
]
}
別のJSONファイル6.jsがありますが、ポイントが得られると思います。最後に魔法...
dojo.require("dojo.parser");
dojo.require("dojo.io.script");
dojo.require("dojox.rpc.Service");
dojo.require("dojox.data.JsonRestStore");
dojo.require("dijit.tree.ForestStoreModel");
dojo.require("dijit.Tree");
dojo.addOnLoad(function(){
var mySmd = {
"SMDVersion": "2.0",
"id": "http://localhost/pretendService.php",
"description": "This is the service to get to the finder app backend data",
transport: "JSONP",
envelope: "URL",
additionalParameters: true,
target: "http://localhost/",
services: {
"getNode": {
"target": "pretendService.php",
parameters: [
{ name: "node", type: "string"}
]
}
}
};
var myService = new dojox.rpc.Service(mySmd);
var myStore = new dojox.data.JsonRestStore({
service : myService.getNode,
idAttribute : "Node_Id",
labelAttribute : "Display_Name"
});
//create forestTreeModel
var treeModelParams = {
store: myStore,
deferItemLoadingUntilExpand: true,
childrenAttrs: ["Children"],
//rootId : "0",
query: "0"
};
var treeModel = new dijit.tree.ForestStoreModel(treeModelParams);
var myTree = new dijit.Tree({
model: treeModel,
id: "myTree",
showRoot: false,
persist: false
});
dojo.byId("treeContainer").appendChild(myTree.domNode);
myTree.startup();
});
</script>
</head>
<body class="tundra">
<div id="treeContainer"></div>
</body>
</html>
ここでの最大の教訓は、データをストアに入れてからその後ツリーに入れる2つの別々の方法(私が従うことができる限り最善)があることです。最初のデータロードはフェッチから来ており、アイテムの配列が期待されます。以下の怠zyなロードされたアイテム(サービスを正しくセットアップし、応答を取得していると仮定して)はloaditemを通過し、その方法はオブジェクトを期待します。
FireBugで応答が表示されているにもかかわらず、最初のロードデータがオブジェクトとして入力されている場合、ページにツリーが表示されません。ただし、エラーはありません。
怠zyなロードされたデータが配列として入力されている場合、「typeerror:args.item is undefined」を取得します - loaditemは2xと呼ばれ、結果オブジェクトの代わりに2回目は空のオブジェクトです。
ストアを作成するときにrootidが定義されている場合、ツリーが表示されず、「指定された階層にノードを挿入できません」エラーが得られます。
上記のエラーはすべて、JSonRestStoreを使用して見つかりました。ドキュメントでは、JsonreststoreがServiceStoreの読み取り機能を継承しているが、2つのストアを切り替えると、「指定された階層にノードを挿入できない」というエラーが発生します。
Dojoに対する私の最大の不満の1つは、実際のデータがデータストアのアイテムに正常に解析される方法を指定するドキュメントの欠如です。データストアの柔軟性とモジュール性については多くの話がありますが、そこに私のデータを取得してそれを機能させる方法はまだ謎です。いつかデータがデータストア項目になる方法についてのSitepenの記事をお持ちです...? :)
これが他の誰かを助けてくれることを願っています。ハッピーコーディング。