Tree组件使用指南之五:点击树节点文字展开或收缩其子节点

时间:2022-08-15 12:39:23
运行环境:JDeveloper 11.1.2.2.0 + Oracle Database 10g Express Edition 10.2.0.1。

默认情况下,只有点击树节点的最左边的三角图标时才能展开或收缩子节点,点击树节点文字时不会展开或收缩子节点。
我们可以通过af:clientListener来实现点击树节点文字时不会展开或收缩子节点功能。

重点步骤说明:

1. 为Tree组件增加ClientListener
Tree组件上发生click事件时将会调用JavaScript函数:expandDiscloseNode。
<af:tree value="#{bindings.DepartmentsView1.treeModel}" var="node"
         selectionListener="#{myBackingBean.treeSelectionListener}" rowSelection="single" id="t1">
    <f:facet name="nodeStamp">
        <af:outputText value="#{node}" id="ot1"/>
    </f:facet>
    <af:clientListener method="expandDiscloseNode" type="click"/>
</af:tree>


2. JavaScript函数:expandDiscloseNode
基本逻辑:找到当前选择的节点(只选择第一个),如果该节点处于展开状态,那么收缩;反之则展开。
function expandDiscloseNode(event) {
    var tree = event.getSource();
    var rwKeySet = tree.getSelectedRowKeys();
    var firstRowKey;
    for (rowKey in rwKeySet) {
        firstRowKey = rowKey;
    }
    if (tree.isPathExpanded(firstRowKey)) {
        tree.setDisclosedRowKey(firstRowKey, false);
    }
    else {
        tree.setDisclosedRowKey(firstRowKey, true);
    }
}


3. 运行
直接点击节点文字,就可以展开或收缩其子节点。

4. 常见错误
经常出现的错误是找不到JavaScript函数,这时要仔细检查JavaScript函数文件的位置。
并且要把该文件使用af:resource放到af:document和af:message之间。
<af:document title="tree_selection_listener.jsf" id="d1">
<af:resource type="javascript" source="resources/js/tree_function.js"/>
<af:messages id="m1"/>

5. 在页面初始化时,展开指定的节点
默认情况下,Tree组件只展开第一层根节点,实际场景中可能希望页面初始化时能够展开指定的节点。
我们可以考虑使用JSF LifeCycle在页面初始化时做一些事情,比如展开两级节点:
Tree组件使用指南之五:点击树节点文字展开或收缩其子节点
实现原理和步骤如下:
(1)在Managed Bean中增加一个方法:beforeRenderResponse(PhaseEvent phaseEvent)
    public void beforeRenderResponse(PhaseEvent phaseEvent) {
        if (phaseEvent.getPhaseId() == PhaseId.RENDER_RESPONSE) {
            FacesContext fctx = FacesContext.getCurrentInstance();
            AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();
      
            boolean isInitialRender = adfFacesContext.isInitialRender();
            if (isInitialRender) {
                UIViewRoot viewRoot = fctx.getViewRoot();
                UIComponent tree = viewRoot.findComponent("t1");
                if (tree != null) {
                    CollectionModel model = (CollectionModel)((RichTree)tree).getValue();
                    JUCtrlHierBinding treeBinding = (JUCtrlHierBinding)model.getWrappedData();
                    JUCtrlHierNodeBinding rootNode = treeBinding.getRootNodeBinding();
                    RowKeySet rks = (((RichTree)tree).getDisclosedRowKeys());
                    if (rks == null) {
                        rks = new RowKeySetImpl();
                    }
                    if (rks.getSize() == 0) {
                        List firstLevelChildren = rootNode.getChildren();
                        for (JUCtrlHierNodeBinding node : firstLevelChildren) {
                            ArrayList l = new ArrayList();
                            l.add(node.getRowKey());
                            rks.add(l);
                        }
                        ((RichTree)tree).setDisclosedRowKeys(rks);
                    }
                }
            }
        }
    }

在RENDER_RESPONSE之前,并且如果是初次请求该页面,那么找到Tree组件,把第2级节点加到DisclosedRowKeys中。
AdfFacesContext提供了三个方法来判断页面的状态:isInitialRender 是否是初次请求;isPartialRequest 是否是局部刷新请求;isPostback 是否是提交表单后的返回请求。
(2)在页面中的f:view中设置beforePhase,指向方法:beforeRenderResponse。
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
beforePhase="#{myBackingBean.beforeRenderResponse}">

Project 下载: ADF_Tree_SelectionListener(3).7z

参考文献:
1. http://www.oracle.com/technetwork/developer-tools/adf/learnmore/20-expand-tree-node-from-label-169156.pdf

2. http://www.oracle.com/technetwork/developer-tools/adf/learnmore/21-expand-tree-on-initial-render-169158.pdf

http://maping930883.blogspot.com/2012/06/adf135tree.html