2

我正在尝试使用 Dojo 工具包实现跨域延迟加载树。到目前为止,我的顶级节点显示正确,但是在单击 expando 时,我收到“延迟已解决”错误,我不知道为什么。通过查看 firebug 网络选项卡,我可以看到 fetch 方法似乎正在工作。我认为我的问题出在我的 _processResults 方法中,可能与其中的 _loadObject 定义有关...

鉴于我一直在努力理解 Dojo,我觉得我应该更好地了解它。但是,唉,它真是一头野兽……我在其中一个 sitepen 博客(http://www.sitepen.com/blog/2008/06/25/web-service )中看到了一些关于 JSONP 和延迟加载的提及-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,但不应该破坏任何东西吗?)

所以我敢肯定,到现在为止,眼睛都在发呆,重申这个问题 - 是什么造成了这个“延期已经解决”的错误?使用 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) . ")" );

?>

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

fakeServiceJson/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>

这里最大的教训是有两种单独的方法(尽我所能)将数据放入存储中,然后再放入树中。第一个数据加载将来自 fetch,它需要一个项目数组。随后的延迟加载项(假设您已正确设置服务并收到响应)将通过 loadItem 并且该方法将需要一个对象。

如果您将初始加载数据作为对象传入,您将不会在页面上看到任何树,尽管在 firebug 中看到了响应。虽然没有错误。

如果您将延迟加载的数据作为数组传入,则会收到“TypeError:args.item 未定义” - 似乎 loadItem 被调用 2x 并且第二次而不是您的结果对象,它是一个空对象。

如果您在创建商店时定义了 rootId,它将不会显示树并给您“无法在指定的层次结构中插入节点”错误。

以上所有错误都是使用 JsonRestStore 发现的。文档说 JsonRestStore 继承了 ServiceStore 的读取功能,但如果我切换出两个存储,我会收到错误“节点无法插入指定的层次结构”。

我对 Dojo 最大的不满之一就是缺少说明如何将实际数据成功解析为数据存储项的文档。有很多关于数据存储的灵活性和模块化的讨论,但是如何将我的数据放入其中并让它工作仍然是一个谜,当我抓住稻草时,这个解决方案就出现了。我很想有一篇关于数据如何成为数据存储项目的网站文章……?:)

我希望这对其他人有帮助。快乐编码。

于 2011-06-17T11:23:10.190 回答