【问题标题】:Dojo JsonRest store and dijit.TreeDojo JsonRest 商店和 dijit.Tree
【发布时间】:2012-06-05 11:54:25
【问题描述】:

我在使用 ForestModel 制作 JSonRest 存储和 dijit.Tree 时遇到了一些问题。我按照网上的许多提示尝试了 JsonRestStore 和 json 数据格式的组合,但没有成功。

最后,这里以表格为例 http://blog.respondify.se/2011/09/using-dijit-tree-with-the-new-dojo-object-store/

我已经制作了这个简单的页面(我使用的是 dojotolkit 1.7.2)

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Tree Model Explorer</title>

<script type="text/javascript">
djConfig = {
parseOnLoad : true,
isDebug : true,
}
</script>
<script type="text/javascript" djConfig="parseOnLoad: true"
src="lib/dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("dijit.Tree");
dojo.require("dojo.store.JsonRest");
dojo.require("dojo.data.ObjectStore");
dojo.require("dijit.tree.ForestStoreModel");

dojo.addOnLoad(function() {

var objectStore = new dojo.store.JsonRest({
target : "test.json",
labelAttribute : "name",
idAttribute: "id"
});

var dataStore = new dojo.data.ObjectStore({

objectStore : objectStore
});

var treeModel = new dijit.tree.ForestStoreModel({
store : dataStore,
deferItemLoadingUntilExpand : true,
rootLabel : "Subjects",
query : {
"id" : "*"
},
childrenAttrs : [ "children" ]
});

var tree = new dijit.Tree({
model : treeModel
}, 'treeNode');
tree.startup();
});
</script>
</head>
<body>

<div id="treeNode"></div>
</body>
</html>

我的休息服务响应以下 json

{
data: [
{
"id": "PippoId",
"name": "Pippo",
"children": []
},
{
"id": "PlutoId",
"name": "Pluto",
"children": []
},
{
"id": "PaperinoId",
"name": "Paperino",
"children": []
}
]}

我也尝试过以下响应(实际上我的最终意图是对树使用延迟加载)

{ data: [
 {
  "id": "PippoId",
  "name": "Pippo",
  "$ref": "author0",
  "children": true
 },
 {
  "id": "PlutoId",
  "name": "Pluto",
  "$ref": "author1",
  "children": true
 },
 {
  "id": "PaperinoId",
  "name": "Paperino",
  "$ref": "author2",
  "children": true
 }
]}

两者都不起作用。 我在萤火虫中没有看到错误消息。 我只是在页面上看到了根“主题”。 感谢任何人都可以以某种方式提供帮助。

【问题讨论】:

    标签: json rest dojo lazy-loading dijit.tree


    【解决方案1】:

    一目了然;

    您的服务器端返回错误的数据。这是 dojo 参考指南中的quickstart jsonrest,请遵循 GET 部分。

    有一个区别,因为您的 REST 请求的外观方式(从浏览器获取),服务器端应该 1)返回一个项目数组或 2)返回一个项目。

    尝试删除 data 键:

    [
      {
        "id": "PippoId",
        "name": "Pippo",
        "children": []
      }, {
        "id": "PlutoId",
        "name": "Pluto",
        "children": []
      }, {
        "id": "PaperinoId",
        "name": "Paperino",
        "children": []
      }
    ]
    

    所以这不会带来延迟加载功能吗?这一定是因为模型在您的代码示例中具有相当复杂的设置,首先是 REST store,然后是 OBJECT another store,然后是 ForestTree model,最后是 Tree view。实现模型必须为我们的商店提供的东西相当简单,让我们跳过双商店的定义。否则 objectstore.query 将调用 reststore.query - 我不完全确定它会起作用。

    RestStore 中缺少逻辑

    树需要五个模型方法来将数据呈现为树:

    1. getIdentity(object) - 商店已经提供,一般不需要重新实现。
    2. mayHaveChildren(object) - 指示对象是否可能有子对象(在实际加载子对象之前)。在此示例中,我们将“children”属性的存在视为有孩子的指示。
    3. getChildren(parent, onComplete, onError) - 调用来找回孩子。这可能会异步执行,并应在完成时调用 onComplete 回调。在此示例中,我们将执行 get() 来检索父对象的完整表示以获取子对象。完全加载父级后,我们从父级返回“子级”数组。
    4. getRoot(onItem) - 调用以检索根节点。应使用根对象调用 onItem 回调。在此示例中,我们获取()根对象的 id/URL 为“root”的对象。
    5. getLabel(object) - 返回对象的标签(这是显示在树中节点旁边的文本)。在此示例中,标签只是对象的“名称”属性。

    那怎么能做到呢?让我们做几个定义:
    1) 服务器集为 jsonrest.target 'base',ID 'root' 和 2) 服务器返回 'children' 键总是,如果有,则为真

    var reststore = JsonRest({
        target:"data/",         // << adapt URL
        mayHaveChildren: function(object){
            // if true, we might be missing the data, false and nothing should be done
            return "children" in object;
        },
        getChildren: function(object, onComplete, onError){
            // this.get calls 'mayHaveChildren' and if this returns true, it will load whats needed, overwriting the 'true' into '{ item }'
            this.get(object.id).then(function(fullObject){
                // copy to the original object so it has the children array as well.
                object.children = fullObject.children;
                // now that full object, we should have an array of children
                onComplete(fullObject.children);
            }, function(error){
                // an error occurred, log it, and indicate no children
                console.error(error);
                onComplete([]);
            });
        },
        getRoot: function(onItem, onError){
            // get the root object, we will do a get() and callback the result
            this.get("root").then(onItem, onError);
        },
        getLabel: function(object){
            // just get the name (note some models makes use of 'labelAttr' as opposed to simply returning the key 'name')
            return object.name;
        }
    });
    

    使用自定义 RestStore 作为模型创建树

    我们使用上面定义的变量 reststore - 并简单地将其设置为树构造参数的模型

    var tree = new dijit.Tree({
      model : treeModel
    }, 'treeNode');
    tree.startup();
    

    服务器端延迟加载 JSON 数据设置

    忽略子数组中的大部分数据,可以减少发送的有效负载,并且可以利用延迟加载。对于收到的每个 One 项目(例如 /data/parents/number1parent),必须填写项目本身的完整表示。如果他/她有孩子,我们需要 1)命名这些以在 view 中获取 labels - 我们使用 'name' 键,参见 getLabel 方法,2) 提供唯一 ID 并 3) 指示他们是否有孩子。

    根 JSON

    {
        "name": "Papparazis",
        "id": "root",
        "children": [
      {
        "id": "PippoId",
        "name": "Pippo",
        // may have children - makes dijit.Tree create expandoNode and events
        "children": true
      }, {
        // example leaf, children == undefined
        "id": "PlutoId",
        "name": "Pluto" 
      }, {
        "id": "PaperinoId",
        "name": "Paperino",
        "children": true
      }
    ]
    }
    

    有了这个,我们将展示

    + 皮波
    * 冥王星
    + 纸片

    任何项目 JSON

    我们是否应该想点击 Pippo 来查看他的子对象,让我们回归;树请求以treeNode.item.children为目标,RestStore 中的设计将其转换为对 object.id==PippoId 的请求 - 并且将使用 this.target/object.parent-relations/object.id shcema 编译 URL。在这种情况下,服务器将通过 GET 以最终 URL data/PippoID 的完整表示进行响应。

    {
        "name": "Pippo",
        "id": "PippoId",
        "surname" : "foo",
        "shoosize" : "bar",
        "children": [
            {
                "name": "Baz",
                "id": "BazId"
            }, {
                "name": "Godfather",
                "id": "GodfatherId",
                "children": true
            }
        ]
    }
    

    请注意,“完整表示对象”(顶层)具有额外的实体,例如 shoosize 和 surname。然而,孩子们仍然是一个“短形式的表示对象”。

    服务器端 PHP Rest 实现

    因此,为了论证,这里表示如何使用 PHP 实现其余功能。我们将假设 papparazies 是 sql-db 中的一个表,并且实现了 getPaparazi($id)getPapasKids($id) 函数来检索数据列。

    首先,我们需要通过 .htaccess 修改告诉 apache 如何处理这个问题。如果您是新手,请查看以下一些资源:

    将它放在 /.htaccess 中,其中 '/' 是您的 DocumentRoot - 并根据需要修改 RewriteBase

    <IfModule mod_rewrite.c>
      RewriteEngine on
      # If your site is running in a VirtualDocumentRoot at http://example.com/,
      # uncomment the following line:
      # RewriteBase /
      # If no file nor a directory exists for the request url,
      # rewrite URLs of the form 'data/object' to the form 'index.php?rest=data/object'.
    
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteCond %{REQUEST_URI} !=/favicon.ico
      RewriteRule ^(.*)$ index.php?rest=$1 [L,QSA]
    
    </IfModule>
    

    从 index.php(所有不存在的文件请求的重写处理程序)中的 PHP 角度来看,我们可以简单地创建以下内容:

    <?php
    
     if(isset($_REQUEST['rest'])) {
    
       // IMPORTANT; validate the request, e.g. check for referrer or similar
    
       $ids = explode("/", $_REQUEST['rest']);
       $pathCount = count($ids);
       $table = array_shift($ids); // as string, 'data/' by example
       if(!$table || $table == "") exit; //  ... validate more
       if($pathCount > 1) {
          $objectRequested = array_pop($ids); // as string '' for root
       }
       if($pathCount > 2) {
          $mid = $ids; // an array, holding rest of the path (middle relatives)
       }
       // with this in hand, we should be able to get the object. 
       // by example we're serving store data for paparazies which 
       // has the 'target' parameter set to 'data/'
       if($table == "data") {
          $fields = getPaparazi($objectRequested);
          $obj = new stdobject();
          $obj->name = $fields['name'];
          $obj->id = $objectRequested;
          $obj->shoosize = $fields['shoosize'];
          $obj->children = array();
          if( ( $children = getPapasKids($objectRequested) ) ) {
              foreach($children as $child) {
                 $c_obj = new stdobject();
                 $c_obj->name = $child['name'];
                 $c_obj->id = $child['id'];
                 if($child['hasChildren']) 
                    $c_obj->children = true;
                 $obj->children[] = $c_obj;
              }
          }
          header("Content-Type: application/x-json; charset=XXXXX");
          print json_encode($obj);
          flush();
          exit;
       }
     }
    ?>
    

    查看 SitePen blog 以获取有关 reststore 和树的编译信息

    【讨论】:

    • 非常感谢 mschr。有了你的建议和一些调整,我能够让它工作,但只是急切地加载。有什么关于延迟加载的建议吗?
    猜你喜欢
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 2013-09-13
    相关资源
    最近更新 更多