- 浏览: 654760 次
- 性别:
- 来自: 成都
文章分类
- 全部博客 (170)
- Android (10)
- Java (35)
- PHP (3)
- Linux (3)
- Powerdesigner (2)
- dedcms (1)
- nginx (1)
- Flex (9)
- REST (2)
- Google App Engine (1)
- mysql (6)
- JAVA开源项目 (1)
- Eclipse (18)
- Eclipse Orion (1)
- Dojo (2)
- UML (1)
- Eclipse GEF EMF (4)
- Eclipse 插件开发 (6)
- OSGI (2)
- DeDeCMS (1)
- Maqetta (2)
- JavaScript (1)
- nginx php (1)
- Dojo V1.7 (2)
- Spring3 (4)
- Hibernate3 (4)
- MongoDB (3)
- Scala (2)
- DSL (1)
- Python (3)
- Maven (1)
- Tomcat (3)
- XMPP (2)
- Apache (4)
- NodeJS (1)
- SQLSERVER (2)
- HTML5 (1)
- Nexus (1)
- web服务器 (2)
- Jetty (2)
- weixin (1)
- ngrok (1)
- 网络与信息安全 (1)
最新评论
-
wangyudong:
配置有点晕,开源社区上找了一个开源的Holer,只需要设置Ac ...
用ngrok实现外网访问本地WEB项目的方法 -
lolo968:
你收集的资料没有链接
基于OSGI的框架开发小结(转) -
smartdog:
使用的maven的版本很老的,而且写的不是很清楚,建议可以参考 ...
Maven多项目依赖配置 -
Tom.X:
OSGi联盟官网:http://osgia.com
基于OSGI的框架开发小结(转) -
Miller003:
你好,我在本地测试时,删除catalina.jar和tomca ...
基于Tomcat7的HTML5 WebSocket 应用示例
对于可视化分级数据的展现,Dojo Tree组件是一个强大的工具。在本指南里,对于迅速和有效的数据钻取到嵌套数据,我们将会考虑如何如何连接tree到数据存储。
Tree 和存储
Dojo Tree组件提供了一个复杂的、常见的、直观的分级数据钻取展现。Tree支持分支的懒加载,使得它对于大数据集有很高的可扩展性。当数据有父子关系时,Tree是一个很有用的widget。
在这里,我们将会学习如何使用新的Dojo对象树存储接口,去迅速构造数据驱动的树结构。在本指南里,为了易于打开章节和折叠我们不使用的章节,我们将会使用一个提供US政府结构的数据源信息并在一个树里显示信息。我们将会从头开始,创建一个简单的对象存储。用带有懒加载、可拖拽的的数据驱动树来结束,并且实时回应数据的变化。
Start with a Store
我们通过创建数据源开始。这个将会是驱动存储树。这里我们将使用JsonRest存储。这个存储使得易于使用数据的懒加载。在这个例子里,我们将展现US政府的层级。这儿是JsonRest存储的一个基本实例,它连接我们的服务器,以至于数据可以通过RESTful重新取回:
require([
"dojo/store/JsonRest"
],
function
(JsonRest) {
usGov =
new
JsonRest({
target:
"data/"
});
});
增加基本数据模型方法
我们将使用我们的存储作为Tree的数据模型。为了做这个,我们也需要去定义模型逻辑,用于描述我们数据的层级。这个Tree需要5个模型方法来呈现数据作为树。
-
getIdentity(object)
- Already provided by the store, and doesn't usually need to be reimplemented. -
mayHaveChildren(object)
- Indicates whether or not an object may have children (prior to actually loading the children). In this example, we will treat the presence of a "children" property as the indication of having children. -
getChildren(parent, onComplete, onError)
- Called to retrieve the children. This may execute asynchronously and should call theonComplete
callback when finished. In this example, we will do aget()
to retrieve the full representation of the parent object to get the children. Once the parent is fully loaded, we return the "children" array from the parent. -
getRoot(onItem)
- Called to retrieve the root node. The onItem callback should be called with the root object. In this example, we get() the object with the id/URL of "root" for the root object. -
getLabel(object)
- Returns the label for the object (this is the text that is displayed next to the node in the tree). In this example, the label is just the "name" property of the object.
现在,让我们来看看如何实现我们数据结构的层级定义。通过在JsonRest实例里定义方法,我们可以比较容易的做到:
usGov = JsonRest({
target:
"data/"
,
mayHaveChildren:
function
(object){
// see if it has a children property
return
"children"
in
object;
},
getChildren:
function
(object, onComplete, onError){
// retrieve the full copy of the object
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
return
object.name;
}
});
用我们的存贮作为数据模型创建Tree
现在,我们可以很容易的把这个存储插入到我们的树中:
require([
"dijit/Tree"
],
function
(Tree) {
tree =
new
Tree({
// create a tree
model: usGov
// give it the model
},
"tree"
);
// target HTML element's id
tree.startup();
});
当Tree启动之后,它将会查询我们的模型/存储的根对象。它将会向存储请求label(通过getLabel())并且得到children。对于每一个child,它将会提供label,如果这个对象可能有children,则增加一个扩展图标。我们的getChildren()
和 getRoot()
函数 委派给 get()
调用,它触发请求到server (using the store's target + the get(id)
argument as the URL for a GET). 服务器用json来回应这些请求去满足模型和Tree。看起来像这样:
延迟加载
为了利用延迟加载的优势,当加载带有孩子的对象时,我们的服务器提供了对象的每一个孩子,但是仅仅在孩子中包含了足够的数据以提供它。这个请求对象是对象的一个“全”展现。然而,对于每一个孩子,仅有name属性、id属性和一个children属性的逻辑值(用于指出是否有孩子),这些孩子对象时有效的部分呈现。延迟加载的这种方法确保了在一个节点展开时,每一次只需要一次请求(而不是每一个展开节点的每一个孩子节点一个请求)。这是我们服务器返回的“root”对象(GET data/root):
{
"name"
:
"US Government"
,
"id"
:
"root"
,
"children"
: [
{
"name"
:
"Congress"
,
"id"
:
"congress"
,
"children"
:
true
},
{
"name"
:
"Executive"
,
"id"
:
"exec"
,
"children"
:
true
},
{
"name"
:
"Judicial"
,
"id"
:
"judicial"
}
]
}
然后,当单击展开一个节点时,Tree将会请求目标对象孩子。这被翻译成父对象全呈现的一个请求。如果我们单击Executive节点,这个存储将会使用目标对象id,并请求完全的"exec"对象,触发请求 GET data/exec。服务器用如下的进行回应:
{
"name"
:
"Executive"
,
"id"
:
"exec"
,
"children"
: [
{
"name"
:
"President"
,
"id"
:
"pres"
},
{
"name"
:
"Vice President"
,
"id"
:
"vice-pres"
},
{
"name"
:
"Secretary of State"
,
"id"
:
"state"
},
{
"name"
:
"Cabinet"
,
"id"
:
"cabinet"
,
"children"
:
true
}
]
}
在这个回应里,你可以看到仅有Cabinet对象也许有孩子。
Tree的用户修改
基于Tree的结构层级的修改,对于drag-n-drop,Tree widget有优秀的支持。如果我们想通过拖拽,允许修改我们的数据,我们可以实现pasteItem()方法和对树设置拖拽控制器。首先,让我们实现pasteItem().当一个拖拽操作发生时,这个方法被调用。pasteItem方法调用的参数如下:
-
child
- The child object that is being pasted. -
oldParent
- The parent object where the child was dragged from. -
newParent
- The new parent of the child object, where the child was dragged to. -
bCopy
- Indicates if the child should be copied (instead of moved). -
insertIndex
- The index of where the child should be placed in the lists of children for the new parent (if the store supports ordering of children).
实现pasteItem的基本方式是简单的。在我们的例子里,我们只是简单的从oldParent孩子数组中移除对象,并且把这个孩子对象添加到newParent孩子数组中。我们通过在oldParent的孩子数组中查找索引来做这个,用splice()去移除它,然后用splice()去把它放置在newParent孩子数组的正确的索引里。我们然后d对于这些父对象中的每一个调用put()去保存修改。然而我们也需要考虑几个并发症。首先,First, the parent objects may or may not be fully downloaded objects. With our lazy loading scheme, only full object's have the children array. Therefore, we will do a get()
on each of the parent's to ensure we have the full object. Next, because there may be alternate copies of objects, we can't do a directindexOf()
call to find the child object in the children, so we need to scan the children to find an object with a matching id. With these considerations in mind, we can craft our pasteItem()
implementation:
usGov =
new
JsonRest({
pasteItem:
function
(child, oldParent, newParent, bCopy, insertIndex){
// make the this store available in all the inner functions
var
store =
this
;
// get the full oldParent object
store.get(oldParent.id).then(
function
(oldParent){
// get the full newParent object
store.get(newParent.id).then(
function
(newParent){
// get the oldParent's children and scan through it find the child object
var
oldChildren = oldParent.children;
dojo.some(oldChildren,
function
(oldChild, i){
// it matches if the id's match
if
(oldChild.id == child.id){
// found the child, now remove it from the children array
oldChildren.splice(i, 1);
return
true
;
// done, break out of the some() loop
}
});
// do a put to save the oldParent with the modified children's array
store.put(oldParent);
// now insert the child object into the new parent,
//using the insertIndex if available
newParent.children.splice(insertIndex || 0, 0, child);
// save changes to the newParent
store.put(newParent);
});
});
},
配置树的拖拽
We then need to define the drag-n-drop controller for the Tree as well. We will use the standarddijit/tree/dndSource
as the controller:
require([
"dijit/Tree"
,
"dijit/tree/dndSource"
,
"dojo/domReady!"
],
function
(Tree, dndSource) {
tree =
new
Tree({
model: usGov,
// define the drag-n-drop controller
dndController: dndSource
},
"tree"
);
});
Now drag-n-drop operations should trigger our pasteItem()
implementation and cause children arrays to be modified and saved. With the JsonRest
store, the modifications that are saved via put()
will trigger HTTP PUT requests to save the data back to the server.
通知
We aren't quite done yet. We need to also notify the Tree
of the changes in the children. The Tree
follows standard MVC principles of responding to data model changes rather than controller actions. This is extremely powerful because the view of the data can respond to changes regardless of what triggered the change (direct programmatic changes, drag-n-drop, etc.). The Tree
listens for the "onChildrenChange
", "onChange
", and "onDelete
" events. The Store API dictates that data updates happen via its put()
method. So we can extend put()
to call these model change methods (triggering the Tree events), and then call the original put()
method to complete the action on the store. Likewise we can call the onDelete
event in the remove()
method:
usGov =
new
JsonRest({
put:
function
(object, options){
// fire the onChildrenChange event
this
.onChildrenChange(object, object.children);
// fire the onChange event
this
.onChange(object);
// execute the default action
return
JsonRest.prototype.put.apply(
this
, arguments);
},
remove:
function
(id){
// We call onDelete to signal to the tree to remove the child. The
// remove(id) gets and id, but onDelete expects an object, so we create
// a fake object that has an identity matching the id of the object we
// are removing.
this
.onDelete({id: id});
// note that you could alternately wait for this inherited add function to
// finish (using .then()) if you don't want the event to fire until it is
// confirmed by the server
},
// we can also put event stubs so these methods can be
// called before the listeners are applied
onChildrenChange:
function
(parent, children){
// fired when the set of children for an object change
},
onChange:
function
(object){
// fired when the properties of an object change
},
onDelete:
function
(object){
// fired when an object is deleted
},
...
编程数据更改
As we mentioned before, the Tree
/model interface is designed so that the Tree
responds to changes regardless of the trigger. Consequently to add a new child, we can simply insert a child object into a parent's children
array, save it with a put()
, and the Tree will automatically respond. In the demo, a button triggers the addition of a child object using the following code:
// get the selected object from the tree
var
selectedObject = tree.get(
"selectedItems"
)[0];
// get the full copy of the object
usGov.get(selectedObject.id).then(
function
(selectedObject){
// add a new child
selectedObject.children.push({
name:
"New child"
,
id:
"new-child-id"
});
// save it with a put(). The tree will automatically update the UI
usGov.put(selectedObject);
});
And, we can remove children with the same approach. We could also change properties of objects, such as the name (the label of the nodes). In the demo, we listen for double-clicks to prompt for a new name for objects:
tree.on(
"dblclick"
,
function
(object){
// node was double clicked, prompt for a new name
object.name = prompt(
"Enter a new name for the object"
);
// save the change, again the tree auto-updates
usGov.put(object);
},
true
);
require([
"dojo/store/JsonRest"
,
"dojo/store/Observable"
,
"dijit/Tree"
,
"dijit/tree/dndSource"
,
"dojo/query"
,
"dojo/domReady!"
],
function
(JsonRest, Observable, Tree, dndSource, query) {
usGov = JsonRest({
target:
"data/"
,
mayHaveChildren:
function
(object){
// see if it has a children property
return
"children"
in
object;
},
getChildren:
function
(object, onComplete, onError){
// retrieve the full copy of the object
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
return
object.name;
},
pasteItem:
function
(child, oldParent, newParent, bCopy, insertIndex){
var
store =
this
;
store.get(oldParent.id).then(
function
(oldParent){
store.get(newParent.id).then(
function
(newParent){
var
oldChildren = oldParent.children;
dojo.some(oldChildren,
function
(oldChild, i){
if
(oldChild.id == child.id){
oldChildren.splice(i, 1);
return
true
;
// done
}
});
store.put(oldParent);
newParent.children.splice(insertIndex || 0, 0, child);
store.put(newParent);
},
function
(error){
alert(
"Error occurred (this demo is not hooked up to a real database, so this is expected): "
+ error);
});
});
},
put:
function
(object, options){
this
.onChildrenChange(object, object.children);
this
.onChange(object);
return
JsonRest.prototype.put.apply(
this
, arguments);
},
remove:
function
(id){
this
.onDelete({id: id});
return
JsonRest.prototype.remove.apply(
this
, arguments);
}
});
tree =
new
Tree({
model: usGov,
dndController: dndSource
},
"tree"
);
// make sure you have a target HTML element with this id
tree.startup();
query(
"#add-new-child"
).on(
"click"
,
function
(){
var
selectedObject = tree.get(
"selectedItems"
)[0];
if
(!selectedObject){
return
alert(
"No object selected"
);
}
usGov.get(selectedObject.id).then(
function
(selectedObject){
selectedObject.children.push({
name:
"New child"
,
id: Math.random()
});
usGov.put(selectedObject);
});
});
query(
"#remove"
).on(
"click"
,
function
(){
var
selectedObject = tree.get(
"selectedItems"
)[0];
if
(!selectedObject){
return
alert(
"No object selected"
);
}
usGov.remove(selectedObject.id);
});
tree.on(
"dblclick"
,
function
(object){
object.name = prompt(
"Enter a new name for the object"
);
usGov.put(object);
},
true
);
});
结论
The Tree
is designed to properly separate the data model concerns from presentation, and the new object store can easily be extended with application hierarchical logic to drive the Tree
. The Tree
provides important features such as keyboard navigation and accessibility. Also, the Tree
and object store combination leverages the additional powerful functionality of the Tree
including scalable lazy loading, drag-n-drop, and real-time response to data model changes. We encourage you to explore the Tree documentation in more depth to learn more about the Tree
capabilities such styling, icon customization, and its API.
相关推荐
- 《Developer's Guide to WINHELP.EXE》(Jim Mischel) - 《Building Windows 95 Help》(Nancy Hickman) - Paul O'Rear - 《Developing Online Help for Windows 95》(Boggan, Farkas, and Welinske) - Gordon F. ...
A minimal Python library for Apache Arrow, connecting to the Rust arrow crate
标题和描述中提到的知识点,首先是关于“ARM-based Serial Synchronous Controller (SSC)”,ARM是一种广泛应用于嵌入式系统的处理器架构,而SSC则是一种同步串行控制器,它能够在许多基于ARM的系统中找到。...
- 循环连接远程机器列表(3.5 Connecting to a List of Remote Machines With in a Loop) - 在脚本中处理连接失败(3.6 Handling Connection Failures With in a Script) 4. 从远程机器读取数据(Chapter 4: ...
Connecting to 222.73.218.96:22... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. Last login: Tue Oct 30 17:09:29 2012 from 114.221.117.202 [root@S2-PC ~]# ifconfig eth0 Link ...
藏经阁-Scaling Spark applications by connecting code to resource co
### 错误十:You don't have permission to access /on this server. 这是服务器权限问题,表示当前用户没有足够的权限访问特定资源。对于Apache服务器,检查配置文件(如httpd.conf)和日志文件(如error.log),...
Chapter 2: Connecting Things to your Pi with GPIO Chapter 3: Extending Your Pi to Connect More Things Chapter 4: Adding a Magnetic Contact Sensor Chapter 5: Adding a Passive Infrared Motion Sensor ...
### 连接Xcelsius仪表板到外部数据源使用Excel 2003 #### 前提条件 为了能够充分利用这份技术指南,读者应当具备以下技术和术语的基础理解: 1. **Excel**: 需要了解如何在Excel中导航及创建公式的基本能力。...
SQL Prompt”充斥着的特点,采取日常工作与SQL出来的,离开你把重点放在棘手位。当你写代码,SQL Prompt建议适当的关键字和查询对象。它甚至可以完成INSERT,ALTER和JOIN声明。为了减少重复输入,SQL Prompt下有一个...
Learn Linux in a Month of Lunches shows you how to install and use Linux for all the things you do with your OS, like connecting to a network, installing software, and securing your system. Whether ...
在描述中提到的"Error connecting to opc 2.0 server browser 没有注册类别"是一个常见的错误,意味着尝试连接到OPC服务器的浏览器组件未能成功注册。这可能是由于以下原因: 1. **注册表问题**:OPC服务器的注册表...
Learn Linux in a Month of Lunches shows you how to install and use Linux for all the things you do with your OS, like connecting to a network, installing software, and securing your system....
The core utilities, known as userland, provide the interface that identifies FreeBSD, both user interface, shared libraries and external interfaces to connecting clients. Currently, 162 people are ...
Oracle Supplier Network Buyer’s Guide to Connecting 11i Release 4.3 Part No. B19153-01