一見すると、
サーバーサイドが間違ったデータを返します。dojo リファレンス ガイドのクイックスタートjsonrest を次に示します。GET 部分に従ってください。
REST リクエストがどのように見えるか (ブラウザーからの GET) の方法により、サーバー側は 1) アイテムの配列を返すか、2) アイテムを返す必要があるため、違いがあります。
次のようにデータキーを削除してみてください。
[
{
"id": "PippoId",
"name": "Pippo",
"children": []
}, {
"id": "PlutoId",
"name": "Pluto",
"children": []
}, {
"id": "PaperinoId",
"name": "Paperino",
"children": []
}
]
では、これはまだ遅延読み込み機能を提供しないのでしょうか? これは、コードのサンプルでモデルが非常に複雑な設定をしているためであるに違いありません。最初に REST store
、次に OBJECT another store
、次に ForestTree model
、最後に Treeview
です。モデルがストアに提供するものを実装するのは非常に簡単で、二重ストアの定義は省略します。それ以外の場合、objectstore.query は reststore.query を呼び出しますが、これが機能するかどうかは完全にはわかりません。
にロジックがありませんRestStore
Treeには、データをツリーとしてレンダリングするための 5 つのモデル メソッドが必要です。
getIdentity(object)
- ストアによって既に提供されており、通常は再実装する必要はありません。
mayHaveChildren(object)
- オブジェクトに子があるかどうかを示します (実際に子をロードする前に)。この例では、「子」プロパティの存在を、子を持つことを示すものとして扱います。
getChildren(parent, onComplete, onError)
- 子を取得するために呼び出されます。これは非同期的に実行される可能性があり、終了時に onComplete コールバックを呼び出す必要があります。この例では、get() を実行して親オブジェクトの完全な表現を取得し、子を取得します。親が完全に読み込まれると、親から「子」配列が返されます。
getRoot(onItem)
- ルート ノードを取得するために呼び出されます。onItem コールバックは、ルート オブジェクトで呼び出す必要があります。この例では、ルート オブジェクトの ID/URL が「root」のオブジェクトを get() します。
getLabel(object)
- オブジェクトのラベルを返します (これは、ツリー内のノードの横に表示されるテキストです)。この例では、ラベルはオブジェクトの「名前」プロパティです。
これはどのように行うことができますか?いくつかの定義を作成しましょう:
1)サーバーはjsonrest.target
「ベース」、ID「ルート」を 設定し、 2)サーバーは常に「子」キーを返し、存在する場合は true
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 をモデルとして Tree を作成する
上記で定義した変数 reststore を使用し、これをツリー構造パラメーターのモデルとして設定するだけです。
var tree = new dijit.Tree({
model : treeModel
}, 'treeNode');
tree.startup();
サーバー側の遅延読み込み JSON データのセットアップ
子配列のほとんどのデータを除外すると、送信されるペイロードを減らすことができ、遅延読み込みを利用できます。受け取った 1 つのアイテム (例: /data/parents/number1parent) ごとに、アイテム自体の完全な表現を入力する必要があります。子供がいる場合は、1) 取得labels
するためにこれらに名前を付ける必要があります。 view
「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
}
]
}
これで、
ROOT
+ Pippo
* Pluto
+ Paperinoを表示します
任意のアイテム JSON
Pippo をクリックして彼の子オブジェクトを表示したい場合は、回帰してみましょう。ツリー リクエスト ターゲットtreeNode.item.children
は、設計上、RestStore で object.id==PippoId のリクエストに変換されます。URL は、this.target/object.parent-relations/object.id
shcema を使用してコンパイルされます。この場合、サーバーはdata/PippoID
GET を介して最終的な URL の完全な表現で応答します。
{
"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)
に withgetPapasKids($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>
PHP の index.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 ブログを参照してください。