我在制作JSonRest存储和dijit时遇到了一些问题。树与森林模型。我按照网络上的许多提示尝试了 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": []
}
]}
我也尝试了以下响应(实际上我的最终意图 n 是对树使用延迟加载)
{ 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
}
]}
两者都不起作用。我在火虫中没有看到错误消息。我只是在页面上看到根"主题"。感谢任何人都可以以某种方式提供帮助。
一目了然;
您的服务器端返回了错误的数据。这是来自 dojo 参考指南的快速入门 jsonrest,请遵循 GET 部分。
这是有区别的,因为你的 REST 请求的外观(来自浏览器的 GET),服务器端应该 1) 返回一个项目数组或 2) 返回一个项目。
尝试删除数据密钥,如下所示:
[
{
"id": "PippoId",
"name": "Pippo",
"children": []
}, {
"id": "PlutoId",
"name": "Pluto",
"children": []
}, {
"id": "PaperinoId",
"name": "Paperino",
"children": []
}
]
所以这不会带来懒惰的装载能力吗?这一定是因为该模型在您的代码示例中具有相当复杂的设置,首先是 REST store
然后是对象another store
,然后是 ForestTree model
,最后是树view
。实现模型必须为我们的商店提供的内容相当简单,让我们跳过双存储定义。否则,objectstore.query 将调用 reststore.query - 我不完全确定它会起作用。
RestStore
中缺少逻辑
树需要五种模型方法将数据呈现为树:
-
getIdentity(object)
- 已由商店提供,通常不需要重新实现。 -
mayHaveChildren(object)
- 指示对象是否可以具有子对象(在实际加载子对象之前)。在此示例中,我们将"子"属性的存在视为有子属性的指示。 -
getChildren(parent, onComplete, onError)
- 打电话来找回孩子。这可能会异步执行,完成后应调用 onComplete 回调。在这个例子中,我们将做一个 get() 来检索父对象的完整表示,以获取子对象。一旦父级完全加载,我们就从父级返回"子项"数组。 -
getRoot(onItem)
- 调用以检索根节点。onItem 回调应与根对象一起调用。在这个例子中,我们得到()一个对象,其中根对象的id/URL为"root"。 -
getLabel(object)
- 返回对象的标签(这是树中节点旁边显示的文本)。在此示例中,标签只是对象的"name"属性。
那怎么可能呢?让我们做几个定义:
1)服务器设置为jsonrest.target
"base",ID"root"和2)服务器返回"子"键,如果有的话,则为真
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 数据设置
省略子数组中的大部分数据,可以减少发送的有效负载并利用延迟加载。对于收到的每件物品(例如/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 和姓氏。然而,孩子仍然是一个"简称代表对象"。
服务器端 PHP Rest 实现
因此,为了论证起见,这里表示如何使用 PHP 实现其余能力。我们将假设papparazies是sql-db中的一个表,并且实现了getPaparazi($id)
和getPapasKids($id)
函数来检索数据列。
首先,我们需要告诉 apache 如何通过 .htaccess 修改来处理这个问题。如果您不熟悉此内容,请查看以下一些资源:
- mod_rewrite:URL重写初学者指南
- 模块mod_rewrite
- 网址重写指南
把它放在/.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>
从索引中的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 博客,了解有关备用仓库和树木的汇编信息