在下拉列表中显示树的组合框

ComboBox that shows a tree in the dropdown

本文关键字:组合 显示 下拉列表      更新时间:2023-09-26

我想编写一个ComboBox,它允许用户键入查询,同时让他从树中选择一个值。我尝试编写树选择,但是如果我将代码更改为从dijit.form.ComboBox而不是dijit.form.Select继承,则代码会中断。

这是我为树选择的树:

dojo.declare('TreeSelect',dijit.form.Select,{
    constructor: function(widgetArgs){
        this.tree = widgetArgs.tree || new FC_Tree();
        this.initTree = widgetArgs.initTree;
        if(dojo.isFunction(this.initTree))
            this.initTree();
    },
    postCreate: function(){
        this.inherited(arguments);
        this.option = {label: '', value: 'NoValue'};
        this.tree.option = this.option;
        this.addOption(this.option);
        dojo.connect(this.tree,'onClick',this,'closeDropDown');
        dojo.connect(this.tree,'itemSelected',this,'selectOption');
    },
    selectOption: function(opt){
        this.option.label = opt.label || opt;
        this.option.value = opt.value || opt;
        this.option.id = opt.id || opt;
        this.set('value',this.option);                      
    },
    _getMenuItemForOption: function (option){
        return this.tree;
    },
    openDropDown: function(){
        this.tree.refresh();
        this.inherited(arguments);
    },
    clear: function(){
        this.tree.clear();
        this.tree.option.value = '';
        this.tree.option.label = '';
        this.tree.option.id = '';
        this.set('value',this.tree.option);
    },
    initializeTree: function(treeData) {
        // Init the tree only if needed
        dojo.forEach(treeData, function(field) {
            var store = this.tree.model.store;
            store.newItem(field);
        }, this);
    },
    setOpenCallback: function(callback){
        this.tree.setOpenCallback(callback);
    },
    resetTree: function() {
        var store = this.tree.model.store;
        store.fetch( { query: { id: "*" },  
            onItem: function(item) {
                store.deleteItem(item);
            }
        });
    }
});

我尝试像这样替换组合框的代码:

dojo.declare('TreeSelect',dijit.form.ComboBox,{

请帮我纠正它。提前感谢!

添加用于FC_Tree的代码:

dojo.declare('FC_Tree',dijit.Tree,{
    showRoot: false,
    openOnClick: true,
    noIconForNode: true,
    noMarginForNode: true,
    persist: false,
    openCallback: null,
    constructor: function(){
        if(dojo.isUndefined(arguments[0]) || dojo.isUndefined(arguments[0].model))
        {
            var forest_store = new FC_DataStore({id: 'id', label: 'label'});
            this._storeloaded = false;
            dojo.connect(forest_store,'loaded',this,function(){this._storeloaded = true;})
            this.model = new dijit.tree.ForestStoreModel({store:forest_store});
        }
    },
    setOpenCallback: function(callback){
        this.openCallback = callback;
    },
    option: {},
    itemSelected: function(item){
    },
    onClick: function(item, node, evt){
        var store = this.model.store;
        get = function(){
            return store.getValue(item, "isDir");
        };
        // on folder click mark it unselectable
        if(get("isDir")) 
        {
            this.isExpanded = true;
            this.isExpandable = true;
        }
        else
        {   //In case the item has 'onClick' delegate execute it and assign the output to 'selItem'
            var selItem = (item.onClick && item.onClick[0])? item.onClick[0](this.model.store,item.parentID[0]):item.id[0]; 
            this.option.id = item.id;
            this.option.value = item.value;
            this.option.label = item.label;
            this.itemSelected(this.option);
        }
    },
    onOpen: function(item, node){
        if(this.rootNode.item == item){
            return this.inherited(arguments);
        }
        var data = (this.openCallback != null) ? this.openCallback(item, node) : {};
        if(!data.length){
            return this.inherited(arguments);
        }
        FC_Comm.when(data,{
            onCmdSuccess: dojo.hitch(this,function(data){
                var store = this.model.store;
                var children = store.getValues(item, 'children');
                dojo.forEach(children, function(child) {
                    // don't delete child if doNotDelete flag is true
                    if(!store.getValue(child, "doNotDelete"))
                        store.deleteItem(child);
                });
                if (data) {
                    var store = this.model.store;
                    if (store) {
                        dojo.forEach(data, function(child) {
                            store.newItem(child, {parent : item, attribute: 'children'});
                        });
                    }
                }
            })
        });
    },
    refresh: function(){
        if(this._storeloaded){
            // Close the store (So that the store will do a new fetch()).
            this.model.store.clearOnClose = true;
            this.model.store.close();
            // Completely delete every node from the dijit.Tree     
            this._itemNodesMap = {};
            this.rootNode.state = "UNCHECKED";
            this.model.root.children = null;
            // Destroy the widget
            this.rootNode.destroyRecursive();
            // Recreate the model, (with the model again)
            this.model.constructor(this.model)
            // Rebuild the tree
            this.postMixInProperties();
            this._load();
            this._storeloaded = false;
        }
    },
    clear: function(){
        this.model.store.load([]);
    }
});

也许你会在这个小提琴中找到灵感/答案

recursiveHunt 和 selectTreeNodeById 函数是通过 id 查找项路径的逻辑。它非常过分,您可能会找到更好的解决方案(不知道 100% 您的 json 是什么样的数据)。

基本上,使用筛选选择并引用此对象中的树。同样对于树,请参阅选择。然后对于你的树,钩接到加载函数(也在刷新 afaik 上调用),反过来对于选择,使用 onBlur 来初始化选择树节点。

var combo = new dijit.form.FilteringSelect({
    onBlur: function() {
        // called when filter-select is 'left'
        if (this.validate()) {
            // only act if the value holds an actual item reference
            var id = this.get("value");
            var name = this.get("displayedValue");
            this.tree.selectNode(id);
        }
    }
});
var tree = new dijit.Tree( {  ....
    onLoad: function() {
        combostore.setData(this.model.store._arrayOfAllItems);
    },
    onClick: function(item) {
        // uses 'this.combo', must be present
        // also, we must have the same 'base store' for both combo and model
        var _name = this.model.store.getValue(item, this.combo.searchAttr);
        this.combo.set("item", item,  false, _name);
    },
    selectNode: function(lookfor) {
        selectTreeNodeById(this, lookfor);
    },
    combo: combo // <<<<<<
});
combo.tree = tree // <<<<<<

确保模型具有rootId,并且您的select.searchAttr与tree.model.labelAttr匹配。查看小提琴上的工作示例