【问题标题】:In-built method to deselect child nodes of a node in ExtJs 4 tree panel在 ExtJs 4 树面板中取消选择节点的子节点的内置方法
【发布时间】:2013-07-31 14:49:17
【问题描述】:

我正在使用 ExtJs 树面板。当您选择该节点时,是否有任何内置方法或属性会取消选择该节点的所有子节点。

所以考虑下图,假设黄色背景的节点已经被选中。如果我现在选择 1.1,系统应该自动取消选择 1.1.2,如果我选择节点 1,它应该取消选择 1.1.2、.1.2.1、1.2.2。

请提供您的建议

Ext.create('Ext.tree.Panel', {
    title: 'Simple Tree',
    renderTo: Ext.getBody(),
    width: 400,
    height: 400,

    store: {
        root: {
            expanded: true,
            children: [{
                text: "1 detention",
                expanded: true,
                "checked": false,
                children: [{
                    text: '1.1 foo',
                    leaf: true,
                    "checked": false
                }, {
                    text: '1.2 bar',
                    leaf: true,
                    "checked": false
                }]
            }, {
                text: "2 homework",
                expanded: true,
                "checked": false,
                children: [{
                    text: "2.1 book report",
                    leaf: true,
                    "checked": false
                }, {
                    text: "2.2 algebra",
                    expanded: true,
                    "checked": false,
                    children: [{
                        text: "2.2.1 buy lottery tickets",
                        leaf: true,
                        "checked": false
                    }, {
                        text: "2.2.2 buy lottery tickets 2",
                        leaf: true,
                        "checked": false
                    }]
                }]
            }, {
                text: "3 buy lottery tickets",
                leaf: true,
                "checked": false
            }]
        }
    },
    useArrows: false,
    rootVisible: false,
    selModel: {
        mode: 'SIMPLE'
    },
    listeners: {
        deselect: function (tree, record) {
            if (record.data.text === '1 detention') {

            }
        },
        select: function (tree, record) {
            var parentNode = record.parentNode;

            // Deselect children
            function deselectChildren(record) {
                tree.deselect(record.childNodes, false);
                record.eachChild(deselectChildren);
            }
            deselectChildren(record);

            // See if all siblings are selected now
            var allSiblingSelected = false;
            if (parentNode) {
                allSiblingSelected = parentNode.childNodes.reduce(function (previous, node) {
                    return previous && tree.isSelected(node)
                }, true);
            }

            if (allSiblingSelected) {
                tree.select(parentNode, true); // will trigger req 1
            }

            // Deselect ancestors
            else {
                while (parentNode) {
                    tree.deselect(parentNode);
                    parentNode = parentNode.parentNode;
                }
            }
        }
    }
});

【问题讨论】:

    标签: extjs tree extjs4


    【解决方案1】:

    不,没有内置这样的东西。哦,现在我想起来了,有些事件是内置在 Ext 中的。你可以抓住一个并在那里实现你自己的逻辑!在您的情况下,这将是 select 事件。

    以下是我建议的完全按照您所描述的方式(使用文档中的示例树面板):

    Ext.create('Ext.tree.Panel', {
        title: 'Simple Tree',
        renderTo: Ext.getBody(),
        width: 400,
        height: 400,
        store: {
            root: {
                expanded: true,
                children: [
                    { text: "detention", leaf: true },
                    { text: "homework", expanded: true, children: [
                        { text: "book report", leaf: true },
                        { text: "algebra", expanded: true, children: [
                            { text: "buy lottery tickets", leaf: true }
                        ]}
                    ] },
                    { text: "buy lottery tickets", leaf: true }
                ]
            }
        },
        rootVisible: false,
        selModel: {
            mode: 'SIMPLE'
        },
        listeners: {
            select: function(tree, record) {
                function deselectChildren(record) {
                    tree.deselect(record.childNodes);
                    record.eachChild(deselectChildren);
                }
                deselectChildren(record);
            }
        }
    });
    

    但这给我们带来了一种非常奇怪的用户体验,因为您可以再次选择子节点,一旦选择了父节点...并触发行为(通过再次单击其祖先来取消选择子节点),您必须先取消选择父级,然后重新选择它...简而言之,IMO,这令人困惑。

    因此,为了让用户更容易预测所有这些事情,我建议在选择节点时取消选择所有祖先,方法是通过以下方式更改 select 侦听器:

    select: function(tree, record) {
        // Deselect children
        function deselectChildren(record) {
            tree.deselect(record.childNodes);
            record.eachChild(deselectChildren);
        }
        deselectChildren(record);
    
        // Deselect ancestors
        var parentNode = record.parentNode;
        while (parentNode) {
            tree.deselect(parentNode);
            parentNode = parentNode.parentNode;
        }
    }
    

    或阻止选择已选择祖先的节点:

    listeners: {
        select: function(tree, record) {
            function deselectChildren(record) {
                tree.deselect(record.childNodes);
                record.eachChild(deselectChildren);
            }
            deselectChildren(record);
        }
        // Returning false from this event handler will prevent selection (see the doc)
        ,beforeselect: function(tree, record) {
            function isAncestorSelected(record) {
                var parentNode = record.parentNode;
                return tree.isSelected(record) || parentNode && isAncestorSelected(parentNode);
            }
            return !isAncestorSelected(record);
        }
    }
    

    但是,如果你想听听我的意见,那第二种行为也有点古怪。我会使用第一个。

    现在,如果您愿意,您可以将所有这些打包到 ux(用户扩展)中,在 Sencha 市场上发布,从那里下载,然后在您的代码中使用它...这样,您将拥有你的行为内置于某些东西;)

    编辑

    要求 1 + 2 + 3 的代码

    Ext.create('Ext.tree.Panel', {
        title: 'Simple Tree',
        renderTo: Ext.getBody(),
        width: 400,
        height: 400,
        store: {
            root: {
                expanded: true,
                children: [
                    { text: "detention", leaf: true },
                    { text: "homework", expanded: true, children: [
                        { text: "book report", leaf: true },
                        { text: "algebra", expanded: true, children: [
                            { text: "buy lottery tickets", leaf: true }
                        ]}
                    ] },
                    { text: "buy lottery tickets", leaf: true }
                ]
            }
        },
        rootVisible: false,
        selModel: {
            mode: 'SIMPLE'
        },
        listeners: {
            select: function(tree, record) {
                var parentNode = record.parentNode;
    
                // Deselect children
                function deselectChildren(record) {
                    tree.deselect(record.childNodes);
                    record.eachChild(deselectChildren);
                }
                deselectChildren(record);
    
                // See if all siblings are selected now
                var allSiblingSelected = false;
                if (parentNode) {
                    allSiblingSelected = parentNode.childNodes.reduce(function(previous, node) {
                        return previous && tree.isSelected(node)
                    }, true);
                }
    
                if (allSiblingSelected) {
                    // EDIT3: adding true for second argument keepExisting
                    tree.select(parentNode, true); // will trigger req 1
                }
    
                // Deselect ancestors
                else {
                    while (parentNode) {
                        tree.deselect(parentNode);
                        parentNode = parentNode.parentNode;
                    }
                }
            }
        }
    });
    

    编辑 4

    带有复选框:

    Ext.create('Ext.tree.Panel', {
        title: 'Simple Tree',
        renderTo: Ext.getBody(),
        width: 400,
        height: 400,
        store: {
            root: {
                expanded: true,
                children: [
                    { checked: false, text: "1 detention", expanded: true, children: [
                        {checked: false, text: '1.1 foo', leaf: true},
                        {checked: false, text: '1.2 bar', leaf: true}
                    ] },
                    { checked: false, text: "2 homework", expanded: true, children: [
                        { checked: false, text: "2.1 book report", leaf: true },
                        { checked: false, text: "2.2 algebra", expanded: true, children: [
                            { checked: false, text: "2.2.1 buy lottery tickets", leaf: true },
                            { checked: false, text: "2.2.2 buy lottery tickets 2", leaf: true }
                        ]}
                    ] },
                    { checked: false, text: "3 buy lottery tickets", leaf: true }
                ]
            }
        },
        rootVisible: false,
        disableSelection: true,
        //selModel: {mode: 'SIMPLE'},
        listeners: {
            checkchange: function(record, checked, opts) {
                if (!checked) return;
                var parentNode = record.parentNode;
    
                // Deselect children
                function deselectChildren(record) {
                    record.eachChild(function(record) {
                        record.set('checked', false);
                        deselectChildren(record);
                    });
                }
                deselectChildren(record);
    
                // See if all siblings are selected now
                var allSiblingSelected = false;
                if (parentNode) {
                    allSiblingSelected = parentNode.childNodes.reduce(function(previous, node) {
                        return previous && node.get('checked');
                    }, true);
                }
    
                if (allSiblingSelected) {
                    parentNode.set('checked', true);
                    // Apparently won't fire on its own
                    this.fireEvent('checkchange', parentNode, true, opts);
                }
    
                // Deselect ancestors
                else {
                    while (parentNode) {
                        parentNode.set('checked', false);
                        parentNode = parentNode.parentNode;
                    }
                }
            }
        }
    });
    

    【讨论】:

    • 我没有询问整个要求,因为这会使这个问题变得非常复杂。这个想法是,1)当您选择一个节点时,我们需要取消选择它的整个子节点(直接或间接)。 2)当你选择所有子节点或节点时,我们需要自动选择其父节点并取消选择所有子节点。
    • 等等...这个答案对您有帮助吗?你的第二个要求也需要帮助吗?您希望或计划如何处理我曝光的问题案例?即在选择父节点后选择子节点。你什么也没说,如果你什么都不做,你最终可能会同时选择父节点和子节点,这显然是你想要避免的......
    • 老实说,我仍在努力理解您发送的代码:-)。但是,如果您真的看第二个要求,那么第一个要求就会处理它。当一个节点的所有兄弟节点都被选中时,我需要做的就是选择父节点,而第一个需求本身将为我解决问题。谢谢
    • 是的,在这种情况下会这样做,但让我烦恼的情况如下。在您的示例中,如果我选择节点 1.1,则将取消选择节点 1.1.1、1.1.2 和 1.1.3,这是第一个要求。但是如果现在我选择节点 1.1.2 怎么办?这不会触发您的任何要求,但我们将在选择节点 1.1 的同时选择其子节点,即节点 1.1.2。看到了吗?
    • 当我们选择一个节点时,我们需要看看,如果它的所有兄弟节点都被选中。如果是,则选择它的父节点(选择父节点将取消选择子节点)。如果否,请选择此节点并取消选择父节点。我应该解释所有这些情况,但我担心这个问题会变得混乱,我可能不会得到任何答复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    相关资源
    最近更新 更多