在制作报表的查询条件时,需要有多选下拉框,Ext 2.3默认没有实现。找来参考资料1的代码测试,发现当有多个多选下拉框时,会有数据混乱不能选择的情况。对其中源码进行了修正,现在可以正常使用。主要修改了初始化[this.selections初始化]和setValue()函数,源码如下:
/**
* 代码Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->Ext.ns('Ext.ux');
* http://www.cnblogs.com/damnedmoon/archive/2010/05/11/1732389.html
*/
Ext.ux.MultiComBox = Ext.extend(Ext.form.ComboBox, {
splitSign : ',',
selections : [],
checks : [],
hiddenValue : '',
lastSelectionText : '',
initList : function() {
var cls = 'x-combo-list';
this.tpl = '
<div class="" '"="">
{' + this.displayField + '}
';
Ext.ux.MultiComBox.superclass.initList.call(this);
this.view.updateIndexes = this.updateIndexes.createDelegate(this.view);
this.view.refresh = this.refresh.createDelegate(this.view, [this], 0);
if (this.view.store) {
this.view.setStore(this.view.store, true);
}
// 再初始化一次,不然多个下拉框时会混用一个变量
this.selections = [];
},
refresh : function(multi) {
this.clearSelections(false, true);
this.el.update("");
var records = this.store.getRange();
if (records.length < 1) {
if (!this.deferEmptyText || this.hasSkippedEmptyText) {
this.el.update(this.emptyText);
}
this.hasSkippedEmptyText = true;
this.all.clear();
return;
}
this.tpl.overwrite(this.el, this.collectData(records, 0));
this.all.fill(Ext.query(this.itemSelector, this.el.dom));
multi.createCheck();
this.updateIndexes(0);
},
updateIndexes : function(startIndex, endIndex) {
var ns = this.all.elements;
startIndex = startIndex || 0;
endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
for (var i = startIndex; i <= endIndex; i++) {
ns[i].viewIndex = i;
if (ns[i].checkbox) {
ns[i].checkbox.index = i;
}
}
},
createCheck : function() {
this.checks = [];
for (var i = 0; i < this.view.all.elements.length; i++) {
var el = this.view.all.elements[i];
var check = new Ext.form.Checkbox({
width : 20,
renderTo : Ext.getBody(),
//readOnly : true,
// 禁用,使点击有效
disabled : true
});
check.initCheckEvents = Ext.emptyFn();
var m = {
index : el.viewIndex,
check : check,
node : el
};
el.checkbox = m;
this.checks.push(m);
Ext.fly(el).select('.check-box').insertFirst(check.wrap);
}
},
findCheckBox : function(index) {
for (var i = 0; i < this.checks.length; i++) {
if (this.checks[i].index == index)
return this.checks[i];
}
return null;
},
onSelect : function(record, index, checked) {
if (this.fireEvent('beforeselect', this, record, index) !== false) {
if (!record)
return;
var checkObj = this.findCheckBox(index);
var checkbox = checkObj && checkObj.check;
if (!checkbox)
return;
if (checked == undefined)
checked = checkbox.checked;
this.toggleCheckBox(index, checked, record, checkbox);
this.select(index, false);// 用来设定选择样式
this.fireEvent('select', this, record, index);
}
},
toggleCheckBox : function(index, checked, r, item) {
if (checked == false) {
item.setValue(1);
if (this.isExist(index) == true)
return;
this.selections.push({
record : r,
index : index
});
} else {
item.setValue(0);
for (var i = 0; i < this.selections.length; i++) {
if (index == this.selections[i].index) {
this.selections.remove(this.selections[i]);
}
}
}
this.setValue(r.data[this.valueField || this.displayField], checked);
},
isExist : function(index) {
for (var i = 0; i < this.selections.length; i++) {
if (this.selections[i].index == index) {
return true;
}
}
return false;
},
setValue : function(v, checked) {
var split = Ext.escapeRe(this.splitSign);
var text = split + this.lastSelectionText + split;
var hiddenValue = split + this.hiddenValue + split;
var values = v.toString().split(this.splitSign);
for (i = 0, l = values.length; i < l; i++) {
var r = this.findRecord(this.valueField, values[i]);
if (r) {
var name = r.data[this.displayField], value = r.data[this.valueField];
var con = Ext.escapeRe(name.toString()), val = Ext
.escapeRe(value.toString());
// var nemeRe = new RegExp("(^" + con + "[" + split + "]?" + ")"
// + "|([" + split + "]?" + con + ")", 'g');
// var valueRe = new RegExp("(^" + val + "[" + split + "]?" + ")"
// + "|([" + split + "]?" + val + ")", 'g');
var nemeRe = new RegExp("(" + split + con + split + ")", 'g');
var valueRe = new RegExp("(" + split + val + split + ")", 'g');
if (checked == false || typeof checked == "undefined") {
text = text.replace(nemeRe, split);
hiddenValue = hiddenValue.replace(valueRe, split);
if (text.length <= 2 * split.length) {
// 空值时
text = split + name + split;
hiddenValue = split + value + split;
} else {
text = text + name + split;
hiddenValue = hiddenValue + value + split;
}
//var separate = !text ? "" : this.splitSign;
} else {
text = text.replace(nemeRe, split);
hiddenValue = hiddenValue.replace(valueRe, split);
if (text.length < 2 * split.length) {
text = split + split;
hiddenValue = split + split;
}
}
}
}
this.lastSelectionText = text.substring(split.length, text.length - split.length);
Ext.form.ComboBox.superclass.setValue.call(this, this.lastSelectionText);
this.hiddenValue = hiddenValue.substring(split.length, hiddenValue.length - split.length);// || this.hiddenValue;
if (this.hiddenField) {
this.hiddenField.value = this.hiddenValue;
}
this.value = this.hiddenValue;
},
getValue : function() {
return Ext.ux.MultiComBox.superclass.getValue.call(this);
},
selectByValue : function(v, scrollIntoView) {
var value = this.getRawValue().trim() || "";
var v1 = value.trim().split(this.splitSign);
for (var i = 0; i < v1.length; i++) {
var v = v1[i];
if (v) {
var r = this.findRecord(this.displayField, v);
this.onSelect(r, this.store.indexOf(r), false);
}
}
},
getRawValue : function(flag) {
var v = this.rendered ? this.el.getValue() : Ext.value(this.value, '');
if (v === this.emptyText) {
v = '';
}
if (flag != true)
return v;
var v1 = v.trim().split(this.splitSign);
if (v1.length > 0) {
var v2 = "";
for (var i = 0; i < v1.length; i++) {
if (v1[i])
v2 = v2 + "(" + v1[i] + ")" + "|";
}
if (v2.length - 2 > 0)
v2 = v2.substring(0, v2.length - 1);
v = new RegExp(v2);
v.length = v2.length;
}
return v;
},
onLoad : function() {
if (!this.hasFocus) {
return;
}
if (this.store.getCount() > 0) {
this.expand();
this.restrictHeight();
if (this.lastQuery == this.allQuery) {
if (this.editable)
this.el.dom.select();
this.selectByValue(this.value, true);
} else {
this.selectByValue(this.value, true)
}
} else {
this.onEmptyResults();
}
},
initQuery : function() {
this.doQuery(this.getRawValue(true));
},
onTriggerClick : function() {
if (this.disabled) {
return;
}
if (this.isExpanded()) {
this.collapse();
this.el.focus();
} else {
this.onFocus({});
if (this.triggerAction == 'all') {
this.doQuery(this.allQuery, true);
} else {
this.doQuery(this.getRawValue(true));
}
this.el.focus();
}
},
reset : function() {
this.clearAll();
Ext.form.ComboBox.superclass.reset.call(this);
},
clearAll : function() {
for (var i = 0; i < this.checks.length; i ++) {
this.checks[i].check.setValue(0);
}
this.lastSelectionText = "";
this.hiddenValue = "";
this.value = "";
this.selections = [];
this.setRawValue("");
Ext.form.ComboBox.superclass.setValue.call(this, "");
}
});
Ext.reg('multiCombox', Ext.ux.MultiComBox);
/*
* Ext.onReady(function() { var myData = [[3300, "彭仁夔"], [3301, "李明"], [3302,
* "王华"], [3303, "张三"], [3304, "李四"], [3305, "王五"], [3306, "彭小明"], [3307, "张华"],
* [3308, "李小"]];
*
* var store1 = new Ext.data.SimpleStore( { fields : [ { name : 'value', type :
* 'string' }, { name : 'name', type : 'string' }], data : myData });
*
* var test = new Ext.ux.MultiComBox( { store : store1, displayField : 'name',
* valueField : 'value', // typeAhead : true, triggerAction : 'all', mode :
* 'local', emptyText : '请选择...', selectOnFocus : true, loadingText :
* 'loading....' }) test.render(Ext.getBody()); });
*/
调用代码跟combox一样,如:
items : [ {
xtype : 'multiCombox',
fieldLabel : '多选数据',
id : 'p_data',
name : 'p_data',
anchor : '95%',
triggerAction : 'all',
valueField : 'name',
displayField : "name",
readOnly : true,
store : dataStore,
mode : 'remote'
} ]
预览效果如图:
参考资料:
[1]Ext JS多选控件 MultiCombo.http://www.cnblogs.com/damnedmoon/archive/2010/05/11/1732389.html