分享ExtJS的下拉树Ext.ux.TreeComboBox,支持Checkbox复选,基于ExtJS3

公司的项目,用到了ExtJS3,而其原生的ComboBox只能选择列表,不能操作树,如果把部门-员工这样的层级结构用ComboBox来展示确实太不直观了。 好在之前在网上搜集了一些关于实现下拉数的资料,但是,貌似都不太适合自己的需求。

结合网上的资料,搞了又重复的造了一个下拉树,加上对ComboBox本身的覆盖重载,可以实现同时获取隐藏域的值(id)和可见域的值(name)。

先说下,对ComboBox的重载。

Ext.override(Ext.form.ComboBox, {
 
      putValue : function(text, value) {
        try {
          var combo = this;
          var displayField = combo.displayField || 'name';
          var valueField = combo.valueField || 'id';
          var index = combo.store.findExact(valueField, value);
          if (index == -1) {
            var r = new combo.store.recordType({});
            r.set(valueField, value);
            r.set(displayField, text);
            combo.store.add(r);
          } else {
            var r = combo.store.getAt(index);
            if (r.get(displayField) != text) {
              r.set(displayField, text);
            }
          }
          combo.setValue(value);
        } catch (err) {
          alert(err);
        }
      },
 
      onRender : function(ct, position) {
        if (this.hiddenName && !Ext.isDefined(this.submitValue)) {
          this.submitValue = false;
        }
        Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
        if (this.hiddenName) {
          this.hiddenField = this.el.insertSibling({
                tag : 'input',
                type : 'hidden',
                name : this.hiddenName,
                id : (this.hiddenId || Ext.id())
              }, 'before', true);
        }
        if (this.visibleName) {
          this.el.set({
                name : this.visibleName
              });
        }
        if (Ext.isGecko) {
          this.el.dom.setAttribute('autocomplete', 'off');
        }
        if (!this.lazyInit) {
          this.initList();
        } else {
          this.on('focus', this.initList, this, {
                single : true
              });
        }
      }
    });


这里新增加了一个“putValue”方法,用于在“编辑”表单上,loadRecord之后,调用本方法给ComboBox赋值。 因为通常情况下,针对远程的ComboBox,直接loadRecord之后显示的是一串id值。

另外,我给ComboBox还加了一个“visibleName”的属性,用来取ComboBox的displayField对应的值,也就是可见的那个值,习惯性以“**Name”来命名,例如”employeeName”,valueField对应的hiddenName通常命名成”employeeId”。

好,背景情况大概就是这样了。


/**
 
* 下拉树,支持ComboBox和TreePanel的大部分配置参数,<br>
 
* 另新增两个配置参数:sm和autoCollpase,其中sm为SelectionModel的简写,支持:'all','folder','leaf';<br>
 
* autoCollapse,布尔值,是否在ComboBox关闭的时候自动关闭树<br>
 
* 特点是可以给树设定最小高度,自动高度,无滚动条支持。
 
*
 
* @class Ext.ux.TreeComboBox
 
* @extends Ext.form.ComboBox
 
* @author xiaosilent<xiaosilent@gmail.com>
 
*/
Ext.ux.TreeComboBox = Ext.extend(Ext.form.ComboBox, {
      folderText : '',
      folderChar : '',
      checkable : false,
      editable : true,
      sm : 'all',
      mode : 'local',
      triggerAction : 'all',
      displayField : 'name',
      valueField : 'id',
      minHeight : 180,
      rootVisible : false,
      autoCollapse : false,
      store : new Ext.data.SimpleStore({
            fields : ['id', 'name'],
            data : [[]]
          }),
 
      initList : function() {
        if (this.list) {
          return;
        }
        this.list = new Ext.Layer({
              cls : 'x-combo-list',
              constrain : true
            });
        this.list.setWidth(Math.max(this.wrap.getWidth(), 100));
        this.view = new Ext.DataView({});
        var combo = this;
        combo.tree = new Ext.tree.TreePanel({
              border : false,
              root : this.root || new Ext.tree.AsyncTreeNode({
                    text : '全部',
                    id : '0'
                  }),
              loader : this.loader,
              renderTo : this.list.id,
              autoScroll : this.autoScroll || true,
              height : this.height,
              rootVisible : this.rootVisible || false,
              bodyCfg : {
                style : 'background-color:#ffffff;  height:' + this.minHeight + 'px; min-height:' + this.minHeight + 'px;'
              },
              tbar : [{
                    text : '展开',
                    handler : function() {
                      combo.tree.expandAll();
                    }
                  }, '-'],
              listeners : {
                'click' : function(node) {
                  if (node.isLeaf()) {
                    if (combo.sm == 'folder') {
                      return;
                    }
                  } else {
                    if (combo.sm == 'leaf') {
                      return;
                    }
                  }
                  if (typeof(node.attributes.checked) == 'undefined') {
                    var tttext, iiid;
                    if (!node.isLeaf() && combo.folderText.length > 0) {
                      tttext = '[' + combo.folderText + ']' + node.text;
                    } else {
                      tttext = node.attributes.parentsText ? node.attributes.parentsText : node.text;
                    }
                    if (!node.isLeaf() && combo.folderChar.length > 0) {
                      iiid = combo.folderChar + '_' + node.id;
                    } else {
                      iiid = node.id;
                    }
 
                    combo.putValue(tttext, iiid);
                    combo.collapse();
                    combo.fireEvent('select', combo, node);
                    combo.el.dom.focus();
                  } else {
                    node.ui.toggleCheck();
                  }
                }
              }
            });
 
        var tbar = combo.tree.getTopToolbar();
 
        if (combo.tree.loader.baseParams.check == true) {
          tbar.add({
                text : '全选',
                handler : function() {
                  combo.tree.root.cascade(function() {
                        this.ui.toggleCheck(true);
                      });
                  tbar.items.get(5).handler.call(this);
                }
              });
        }
 
        tbar.add({
              text : '清空',
              handler : function() {
                combo.tree.root.cascade(function() {
                      this.ui.toggleCheck(false);
                    });
                combo.clearValue();
                combo.collapse();
              }
            });
 
        if (combo.tree.loader.baseParams.check == true) {
          tbar.add('-', {
                text : '确认',
                handler : function() {
                  if (combo.tree.loader.baseParams.check == true) {
                    var checked = combo.tree.getChecked();
                    var names = "", ids = "";
                    for (var i = 0; i < checked.length; i++) {
                      var node = checked[i];
                      if (!node.isLeaf() && combo.folderText.length > 0) {
                        names += "[" + combo.folderText + "]" + node.text + ",";
                      } else {
                        names += node.text + ",";
                      }
                      if (!node.isLeaf() && combo.folderChar.length > 0) {
                        ids += combo.folderChar + "_" + node.id + ",";
                      } else {
                        ids += node.id + ",";
                      }
                    }
                    if (names.length > 1) {
                      names = names.substring(0, names.length - 1);
                    }
                    if (ids.length > 1) {
                      ids = ids.substring(0, ids.length - 1);
                    }
                    combo.putValue(names, ids);
                    combo.setValue(ids);
                    combo.fireEvent('select', combo);
                    combo.fireEvent('change', combo, ids);
                  }
                  combo.collapse();
                }
              });
        }
 
        tbar.doLayout();
 
        this.tree.root.on('load', function(node) {
              if (combo.autoSelect && node.childNodes.length == 1) {
                function selectFirstNode() {
                  node.childNodes[0].select();
                  combo.tree.fireEvent('click', node.childNodes[0]);
                  node.un('expand', selectFirstNode);
                }
                node.on('expand', selectFirstNode);
              }
            });
 
        this.innerList = this.list.createChild();
      },
 
      onKeyUp : function(e) {
        var k = e.getKey();
        if (this.editable !== false && this.readOnly !== true && (k == e.BACKSPACE || !e.isSpecialKey())) {
 
          this.lastKey = k;
          this.dqTask.delay(500); 
// 将这里强制修改成500,而不是this.queryDelay,因为mode是指定的local啊~~~
        }
        Ext.form.ComboBox.superclass.onKeyUp.call(this, e);
      },
 
      doQuery : function(q, forceAll) {
        q = Ext.isEmpty(q) ? '' : q;
        var qe = {
          query : q,
          forceAll : forceAll,
          combo : this,
          cancel : false
        };
        if (this.fireEvent('beforequery', qe) === false || qe.cancel) {
          return false;
        }
        q = qe.query;
        forceAll = qe.forceAll;
        if (q.length >= this.minChars) {
          if (this.lastQuery != q) {
            this.lastQuery = q;
            if (q.length >= this.minChars) {
              combo = qe.combo;
              combo.tree.loader.baseParams.query = q;
              combo.tree.root.reload();
            }
            this.expand();
          } else {
            this.selectedIndex = -1;
            this.onLoad();
          }
        }
      },
 
      collapse : function() {
        if (this.autoCollapse) {
          this.tree.collapseAll();
        }
        Ext.ux.TreeComboBox.superclass.collapse.call(this);
      }
    });
 
Ext.reg('treecombo', Ext.ux.TreeComboBox);

这里有几个约定
1、就是这对loader的baseParams,如果里面有:check:true,那么就认为是一个带复选框的树形结构,那么,tbar上就增加了“全选”和“确认”两个按钮。这里要求loader对应的url能够识别check这个参数,并在check=true的时候,返回的JSON上,带“checked”属性。

当然我实际应用的时候,baseParams里还会加上checked参数,提供一个“默认选中”的id列表,url可以识别并把这些id对应的node的checked属性设置成true,展开树时就默认选上了。

2、关于sm的约定:这只有在baseParams里面没有check:true参数时才有效。 默认sm是’all’,表示leaf和folder节点都可以被选中,当被设置成’leaf’或’folder’之后,则只有对应的节点才可以被选中。 比如我们在选择员工的时候,按照部门-员工的层级结构展开,把sm设置成’leaf’就表示只能选择员工而不能选择部门啦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
校园失物招领系统管理系统按照操作主体分为管理员和用户。管理员的功能包括字典管理、论坛管理、公告信息管理、失物招领管理、失物认领管理、寻物启示管理、寻物认领管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 校园失物招领系统管理系统可以提高校园失物招领系统信息管理问题的解决效率,优化校园失物招领系统信息处理流程,保证校园失物招领系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 ,管理员权限操作的功能包括管理公告,管理校园失物招领系统信息,包括失物招领管理,培训管理,寻物启事管理,薪资管理等,可以管理公告。 失物招领管理界面,管理员在失物招领管理界面中可以对界面中显示,可以对失物招领信息的失物招领状态进行查看,可以添加新的失物招领信息等。寻物启事管理界面,管理员在寻物启事管理界面中查看寻物启事种类信息,寻物启事描述信息,新增寻物启事信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值