使用t:tree2(x:tree2同)可以帮我们完成树的展现,但是对于数据量较大(如超过1万条)的树,一次性加载到客户端将很慢,因此通常做法是(这里举例银行机构)初次读取总行及一级分行,当用户想查看某一分行(如浙江行)所辖的二级分行时,再取出浙江行所辖的二级行,这个过程读取和传送的数据量是很小的。
但是t:tree2本身不提供动态加载数据的功能,而且由于程序员无法捕捉点击+及-事件。但是我们可以试着通过替换树的+和-,并使用自己的+和-以捕捉到用户的请求。具体做法如下:
注意:需要使用x:saveState保存树的状态
<x:tree2 value="#{deptTreeBean.deptRoot}" id="client-tree" var="node"
varNodeToggler="t" clientSideToggle="false" showNav="false"
showLines="false" showRootNode="false">
<f:facet name="DEPT">
<h:panelGroup>
<f:facet name="expand">
</f:facet>
<f:facet name="collapse">
</f:facet>
<h:panelGrid columns="3" id="panel">
<h:commandLink immediate="true" οnclick="getId(this.id);" action="#{t.toggleExpanded}"
rendered="#{!t.nodeExpanded && node.haschild}" actionListener="#{deptTreeBean.findSubUnitBySuperUnitId}">
<x:updateActionListener property ="#{deptTreeBean.superUnitTreeNode}" value="#{node}" />
<x:graphicImage value="/images/nav-plus.gif" border="0"/>
</h:commandLink>
<h:commandLink immediate="true" οnclick="getId(this.id);" action="#{t.toggleExpanded}" rendered="#{t.nodeExpanded && node.haschild}">
<x:graphicImage value="/images/nav-minus.gif" border="0"/>
</h:commandLink>
<h:outputText value="" rendered="#{!node.haschild}" style="width:19px"/>
<h:panelGroup>
<h:commandLink id="link" value=""/>
<h:outputText value="#{node.description}" />
</h:panelGroup>
</h:panelGrid>
</h:panelGroup>
</f:facet>
</x:tree2>
如上面代码所示,属性showNav=false时,系统不显示+和-(收缩图标),然后,我们自己将图标放上去,并捕捉点击事件即可。蓝色部分的代码是为了保证子节点相对于父节点有缩进,使得树形结构清晰。
对应的backingbean代码示例如下:
其中:UnitTreeNode 需要extends TreeNodeBase,且至少增加两个属性:(1)、added属性:boolean,表示该节点是否已经在加载过其子节点。(2)、haschild属性:boolean ,表示是否有子节点
/**
* 部门单选树
*
* @author minnanlin88
*
*/
public class DeptTreeBean extends BaseBean {
// 部门树根节点
private UnitTreeNode deptRoot;
// 点中的节点
private UnitTreeNode superUnitTreeNode;
/* 其它代码略 */
/**
* 监听事件:当有节点被展开时,取该节点的所有直接下级子节点
*/
public String findSubUnitBySuperUnitId(ActionEvent e) {
try {
if (superUnitTreeNode != null) {
// 已经加载过了,不去去数据库
if (superUnitTreeNode.isAdded()) {
return null;
}
}
String currDeptId = superUnitTreeNode.getIdentifier().trim();
// 找到直接下级
List juniorOrgs = yourService.getDirectSubOrg(
currDeptId);
if (juniorOrgs != null && !juniorOrgs.isEmpty()) {
// 根据需要进行排序
UnitComparator com = new UnitComparator();
Collections.sort(juniorOrgs, com);
// 遍历,并将子节点加进来
Iterator it = juniorOrgs.iterator();
while (it.hasNext()) {
Unit unit = (Unit) it.next();
UnitTreeNode treeNode = new UnitTreeNode("DEPT", unit
.getUnitId(), unit.getUnitName(), false, "");
// 置刚加进来的子节点的added值为false,表示他们都没有加载子节点
treeNode.setAdded(false);
int sub_count= yourservices.getAllSubCount(unit.getUnitId());
if (sub_count=0)
treeNode.setHaschild(false);
else
treeNode.setHaschild(true);
// 添加子节点到树的数据模型中
this.superUnitTreeNode.getChildren().add(treeNode);
// 置当前节点已加载过子节点
this.superUnitTreeNode.setAdded(true);
}
}
if (this.superUnitTreeNode.getChildCount() == 0) {
this.superUnitTreeNode.setHaschild(false);
}
} catch (Exception ex) {
this.handleException(ex);
}
return null;
}
}
【另】由于点击后,页面刷新,所以往往在查看位置处在比较底下的分行的所辖二级行时,页面一旦刷新,用户不能定位到该分行,还要再次寻找,造成使用上的不便,因此建议加上自动定位功能(或使用ajax,未验证,不知道可否),这里采用的是再每个节点增加一个链接,点击节点时记录该节点的位置,刷新完后,系统自动重新找到该节点并显示。做法是:
在节点前加上<h:commandLink id="link" value=""/> 系统自动点击link即可定位到该节点,οnclick="getId(this.id);" 的作用就是取得节点的位置,存放在隐藏域里。
页面加载时执行init()方法:
function init()
{
// 自动定位
var pre_id=document.getElementById("form1:id").value;
document.getElementById("goto2").href="#"+pre_id+":link";
document.getElementById("goto2").click();
}
// 获取ID的前缀,由于JSF的render所产生的id是有规律可循的,如当前树节点的ID是
// form1:client-tree:_id25:_id01那么,在其前面的链接link的ID必然为form1:client-tree:_id25:link
function getId(str)
{
var arr=str.split(":");
var newstr="";
if(arr.length>1)
{
for(var i=0;i<arr.length-1;i++)
{
if(i==0)
newstr=arr[i];
else
newstr+=":"+arr[i];
}
}
document.getElementById("form1:id").value=newstr;
}