2

Dojo ツールキットを使用して、クロスドメインの遅延読み込みツリーを実装しようとしています。これまでのところ、トップ レベルのノードは正しく表示されていますが、expando をクリックすると、「遅延は既に解決されています」というエラーが表示され、その理由がわかりません。firebug のネットワーク タブを見ると、fetch メソッドが機能しているように見えます。私の問題は _processResults メソッド内にあると思います。おそらく、その中の _loadObject の定義に関係しています...

Dojo を理解しようと多くの時間を費やしてきたので、Dojo についてもっとよく知る必要があると感じています。しかし、悲しいかな、それはかなりの野獣です... サイトペンのブログの 1 つで、JSONP と遅延読み込みが機能しないという言及を見たことがあります ( http://www.sitepen.com/blog/2008/06/25/web-service -data-store/ )、しかし、JSONP が非同期であること以外にそれが可能であってはならない理由については言及されていません。Dojo が入ってくる json データを単にストアに詰め込もうとしているのなら、なぜそれが重要なのか理解できません。

おそらく、それは私のデータのフォーマットに関係しています - サイトペンの別の例 ( http://www.sitepen.com/blog/2010/01/27/effective-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 は必要ないかもしれませんが、何かを壊すことはありませんか?)

ですから、問題をもう一度述べるために、今では目が輝いていると確信しています-この「延期されたものはすでに解決されています」というエラーを作成しているのは何ですか? JSONPでツリーへの遅延ロードは可能ですか? 別の json 構造を使用すると、遅延読み込みの問題を解決できますか? Dojo 内で自分のデータを再フォーマットして、それが機能するようにすることはできますか? (私はそれが _processResults メソッドのポイントだと思っていました...) 練習する公開されたツリー データサービスはありますか?

みんな、ありがとう!

4

1 に答える 1

2

多くの実験と欲求不満の後、これらは私の発見です:

はい、JSONP を使用してツリーの遅延読み込みが可能です。はい、データを別の形式にすると、遅延読み込みの問題が解決されました。途中でいくつかのつまずきを見つけましたが、これについては後述します。

これが実用的な実装のコードです。最初のサービス:

ふりサービス.php

$callback = $_GET["callback"];
$nodeName = $_GET["node"];
$fileName = "pretendServiceJson/".$nodeName.".js";

print($callback . "(" . file_get_contents($fileName) . ")" );

?>

putServiceJson/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"
      }
   ]
}
]

putServiceJson/3.js - これは最初の遅延読み込みアイテムになります -オブジェクトであることに注意してください!!!

{
    "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 つの別々の方法 (私が従うことができる限り) があるということです。最初のデータロードはフェッチから行われ、アイテムの配列が必要です。後続の遅延ロードされた項目 (サービスを正しくセットアップし、応答を取得していると仮定) は loadItem を通過し、そのメソッドはオブジェクトを期待します。

オブジェクトとして入ってくる初期ロード データがある場合、firebug で応答が表示されても、ページにツリーは表示されません。エラーはありませんが。

遅延ロードされたデータが配列として入ってくると、「TypeError: args.item is undefined」が表示されます.loadItemが2回呼び出され、結果オブジェクトの代わりに2回目が空のオブジェクトになるようです.

ストアの作成時に rootId が定義されている場合、ツリーは表示されず、「指定された階層にノードを挿入できません」というエラーが表示されます。

上記のエラーはすべて、JsonRestStore を使用して検出されました。ドキュメントには、JsonRestStore が ServiceStore の読み取り機能を継承すると書かれていますが、2 つのストアを切り替えると、「指定された階層にノードを挿入できません」というエラーが表示されます。

Dojo に対する私の最大のフラストレーションの 1 つは、実際のデータをデータ・ストアのアイテムに正しく解析する方法を指定する文書がないことです。データ ストアの柔軟性とモジュール性については多くの議論がありますが、そこにデータを取得して機能させる方法はまだ謎であり、ストローをつかんだときにこの解決策が思い浮かびました。いつかデータがどのようにデータストア アイテムになるかについてのサイトペン記事があればいいのですが...? :)

これが他の誰かに役立つことを願っています。ハッピーコーディング。

于 2011-06-17T11:23:10.190 に答える