在ExtJs 4树面板中取消选择节点子节点的内置方法

在ExtJs 4树面板中取消选择节点子节点的内置方法,extjs,tree,extjs4,Extjs,Tree,Extjs4,我使用的是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,

我使用的是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;
                }
            }
        }
    }
});


不,没有这种内置的东西。哦,现在我想起来了,有一些事件是内置在Ext中的。你可以捕捉到一个事件并在其中实现你自己的逻辑!在你的情况下,就是这样

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

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

因此,为了让用户更容易预测所有这些内容,我建议在选择节点时通过以下方式更改
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。看到了吗?当我们选择一个节点时,我们需要查看它的所有同级节点是否都被选中。如果是,请选择它的父节点(选择父节点将取消选择子节点)。如果否,请选择此节点并取消选择父节点。我本应解释所有这些情况,但我担心问题会变得混乱,我可能得不到任何答复。
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;
                }
            }
        }
    }
});