日期:2014-05-16  浏览次数:20419 次

ExtJs 3 自定义combotree
/**
 * 自定义下拉树,支持初始化值时自动定位树节点。
 * 还没有考虑性能问题。继承自Ext.form.ComboBox也很浪费。
 * 代码中的cu.get()是自定义的异步请求方法。
 * @author Linzongxue
 * @create_date 2011-12-13
 */
Ext.ux.ComboBoxTree = Ext.extend(Ext.form.ComboBox, {
	//树的配置项
	dataUrl: null, //获取树所有节点的url
	//通过id获取某个节点的id全路径的url,返回值的格式应该是:parentId1/parentId2/parentId3/../节点id
	//如果不设置这个值,下拉树不会自动定位节点并在初始化时显示文本
	nodePathUrl: null,
	loader: null,
	root: {},
	rootVisible: false,
	//树的选择模式
	rootSelectable: false, //根节点是否可选,默认为false
	folderSelectable: true, //目录是否可选,默认为true
	leafSelectable: true, //叶子是否可选,默认为true
	showFullPath: false, //是否显示全路径
	rootValue: undefined, //根节点的值(通常根节点的取值与普通节点的取值不一样,如果一样则不需要设置此值)
	//原combo类的配置项
	store: new Ext.data.SimpleStore({fields:[],data:[[]]}),
	mode: 'local',
	triggerAction: 'all',
	editable: false,
	forceSelection: true,
	tree: null, //树控件,在expand方法中初始化
	//private: 用于防止combo收缩,在树的事件中控制此属性值
	preventCollapse: false,
	
	initComponent: function(){
		this.treeId = Ext.id();
		this.height = this.height || 200;
		this.tpl = String.format('<tpl for="."><div id="{0}" style="height:{1}px"></div></tpl>', this.treeId, this.height);
		Ext.ux.ComboBoxTree.superclass.initComponent.call(this);
	},
	setValue: function(value){
		if (Ext.isObject(value)){ //点击树节点时的选择
			this.doSetValue(value);
		}
		else{ //只是设置一个值,从后台获取这个值的路径,并在树中选中这个节点
			//console.log(value);
			if (!this.tree) this.initTree();
			if (value === this.tree.root.id || 
					(Ext.isDefined(this.rootValue) && value === this.rootValue)){ //根节点
				this.tree.root.select();
				this.doSetValue(this.root);
				return;
			}
			var url = this.nodePathUrl;
			if (!url){
				this.doSetValue({id: value});
				return;
			}
			cu.get(url, {id: value}).done(function(path){//从后台发起请求获取id路径
				path = '/' + this.root.id + (path.indexOf('/') == 0 ? '' : '/') + path;
				var comboTree = this;
				this.tree.selectPath(path, 'id', function(success, node){
					comboTree.doSetValue(success ? node : null);
				});
			}, this);
		}
    },
    //private:设置值,参数value应该是一个对象
    doSetValue: function(value){
    	var id = value ? value.id : '';
    	var text = value ? value.text : '';
    	if (value && (value.loader || value.attributes)){ //是树节点
    		var isRootNode = (value.id == this.tree.root.id);
    		if (isRootNode && Ext.isDefined(this.rootValue)){
    			id = this.rootValue;
    		}
            if (this.showFullPath){
            	text = isRootNode ? '/' : value.getPath('text').replace('/' + this.tree.root.text, '');
            }
    	}
		this.value = id;
		if(this.hiddenField){
			this.hiddenField.value = id; //设置表单域
		}
		this.lastSelectionText = text;
		this.el.dom.value = text; //显示的值
        this.fireEvent('select', this, value);
    },
    getValue : function(){
    	return Ext.isDefined(this.value) ? this.value : '';
    },
    //取得选中的树节点
	getValueNode: function(){
		return this.tree ? this.tree.getSelectionModel().getSelectedNode() : null;
	},
	getText: function(){
		return this.lastSelectionText || '';
	},
	reload: function(){
		if (!this.tree) return;
		var node = this.tree.getSelectionModel().getSelectedNode();
		var path = node ? node.getPath() : null;
		this.tree.getLoader().load(this.tree.root, function(){
			if (path) {
				this.tree.selectPath(path);
			}
		}, this);
		this.preventCollapse = true;
	},
    //private: 根据preventCollapse属性判断是否要收缩
	collapse: function(){
		if (this.preventCollapse){
			this.preventCollapse = false;
			return;
		}
		Ext.ux.ComboBoxTree.superclass.collapse.call(this);
	},
	//private:
	expand : function(){
		Ext.ux.ComboBoxTree.superclass.expand.call(this);
		if (!this.tree){
			this.initTree();
		}
    },
    //private:
    destroy: function(){
    	if (this.tree && this.tree.rendered) this.tree.destroy();
    	Ext.form.ComboBox.superclass.destroy.call(this);
    },
    //private
    initTree: function(){
    	if (!this.list){ //必须先初始化列表,在一开始就设置了combotree的值时尤其重要,发现这个问题花了半天时间