Ленивая загрузка дерева додзё на основе JsonRestStore и jsonp - PullRequest
2 голосов
/ 16 июня 2011

Я пытаюсь реализовать междоменное, ленивое дерево загрузки с помощью инструментария Dojo. До сих пор у меня правильно отображались узлы верхнего уровня, но при щелчке по кнопке "экспло" я получаю сообщение об ошибке "отложенное решение уже разрешено", и я не уверен, почему. Я вижу, что метод fetch работает, глядя на вкладку сети firebug. Я думаю, что моя проблема в моем методе _processResults, возможно, это связано с определением внутри него _loadObject ...

Я чувствую, что должен знать Додзё лучше, учитывая всё время, которое я потратил, пытаясь понять это. Но, увы, это чудовищно ... Я видел упоминание о том, что JSONP и lazyload не работают в одном из блогов sitepen (http://www.sitepen.com/blog/2008/06/25/web-service-data-store/), но там не упоминается, почему это невозможно кроме того, что JSONP является асинхронным. Если Dojo собирается просто поместить входящие данные json в хранилище, я не понимаю, почему это должно иметь значение.

Возможно, это связано с моим форматированием данных - другой пример на sitepen (http://www.sitepen.com/blog/2010/01/27/efficient-lazy-loading-of-a-tree/) при использовании jsonreststore не загружает элемент, пока вы не развернете узел, тогда как мой формат загружает элемент, но не загружает дочерние элементы узлы, пока вы не расширите его ...

Без лишних слов, вот кодекс ...

<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 ...) Есть ли какие-либо общедоступные древовидные устройства данных, на которых можно попрактиковаться?

Спасибо всем!

1 Ответ

2 голосов
/ 17 июня 2011

После долгих экспериментов и разочарований это мои выводы:

Да, отложенная загрузка дерева возможна с использованием JSONP. Да, перевод моих данных в другой формат помог в решении проблемы отложенной загрузки. По пути я нашел несколько камней преткновения, о которых я упомяну позже.

Вот код для работающей реализации. Первый сервис:

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 - это будет первый ленивый загруженный элемент - примечание это объект !!!

{
    "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>

Самый большой урок здесь состоит в том, что есть два отдельных метода (насколько я могу судить лучше), которые помещают данные в хранилище, а затем в дерево. Первый набор данных будет получен из выборки, и он будет ожидать множество элементов. Следующие лениво загруженные элементы (при условии, что вы правильно настроили службу и получаете ответы) будут проходить через loadItem, и этот метод будет ожидать объект.

Если у вас есть данные начальной загрузки, поступающие как объект, вы не увидите дерева на своей странице, несмотря на то, что видите ответ в firebug. Никаких ошибок, хотя.

Если у вас есть лениво загруженные данные, поступающие в виде массива, вы получаете «TypeError: args.item не определен» - кажется, что loadItem вызывается 2x, и второй раз вместо вашего результирующего объекта это пустой объект. 1033 *

Если у вас есть rootId, определенный при создании хранилища, оно не будет отображать дерево и выдает ошибку «Невозможно вставить узел при указанной иерархии».

Все вышеперечисленные ошибки были обнаружены с помощью JsonRestStore. В документации говорится, что JsonRestStore наследует функциональность чтения ServiceStore, но если я переключаю два хранилища, я получаю ошибку «Узел не может быть вставлен в указанную иерархию».

Одно из моих самых больших разочарований в Dojo - просто отсутствие документации, указывающей, как фактические данные успешно анализируются в элементах для хранилищ данных. Много говорят о гибкости и модульности хранилищ данных, но как получить мои данные и заставить их работать, до сих пор остается загадкой, и это решение пришло мне в голову, когда я ухватился за соломинку. Я хотел бы написать на сайте статью о том, как данные когда-нибудь станут элементами хранилища данных ...? :)

Надеюсь, это поможет кому-то еще. Удачного кодирования.

...