EXTJS记事本:CompositeField与RowEditor结合
作者:技术拾光时间:2026-06-12 08:32:07浏览:336
在RowEditor中利用CompositeField嵌入三个ComboBox实现物料级联筛选,需手动处理控件初始化与Change事件。通过扩展afterstart事件进行控件赋值,在validateedit中校验重复物料,并在afteredit中手动将值写回记录。关键是通过editor.items.items[0]访问CompositeField子组件。
背景与挑战
在进行BOM(物料清单)编辑时,经常需要在同一个RowEditor中处理级联下拉选择,这在实际开发中并不容易实现。客户的物料种类超过一千种,若仅使用单个ComboBox,查找效率极低。因此,方案设计为通过“物料分类”和“物料品牌”两个ComboBox构建级联筛选。但在RowEditor的一个字段内嵌入多个控件,需要手动管理每个控件的初始化和Change事件。经过三天的调试,最终实现了完整方案。
RowEditor定义与事件处理
首先定义RowEditor实例,并设置保存、取消等文本内容。
var editor=new Ext.ux.grid.RowEditor({
saveText: '确定',
cancelText: "放弃",
commitChangesText: '请确定或放弃修改',
errorText: '错误'
});
// 取消编辑时,若关键字段值为空则删除空记录
editor.on("canceledit", function(editor, pressed) {
if (pressed && editor.record.get("materialid") == 0) {
store.remove(editor.record);
}
}, this);
/**
* afterstart事件为自行扩展,在RowEditor显示后立即触发,适合初始化自定义控件。
* 通过editor.items.items[0]访问CompositeField组件,注意RowEditor的items不是数组而是对象。
* 最后一个ComboBox的数据依赖前两个级联选取,需在callback中动态加载数据。
*/
editor.on("afterstart", function(editor, rowIndex) {
var record = store.getAt(rowIndex);
editor.items.items[0].items.items[0].setValue(record.get("setid"));
editor.items.items[0].items.items[1].setValue(record.get("category"));
var t_store = editor.items.items[0].items.items[2].getStore();
t_store.load({
params: { category: record.get("category"), setid: record.get("setid") },
callback: function(r, options, success) {
if (success)
editor.items.items[0].items.items[2].setValue(record.get("materialid"));
}
});
}, this);
/**
* validateedit事件在点击确认时触发,添加自定义校验:禁止重复物料。
* 遍历store中的记录,若物料值重复则提示并删除当前记录。
*/
editor.on("validateedit", function(editor, obj, record, rowIndex) {
var materialid = editor.items.items[0].items.items[2].getValue();
var exist = false;
Ext.each(store.getRange(), function(o, i) {
if (o != record && o.get("materialid") == materialid) {
exist = true;
return (false);
}
});
if (exist) {
Ext.MessageBox.alert("系统提示", "请勿重复添加");
store.remove(record);
}
return (!exist);
}, this);
/**
* afteredit在通过校验后执行。由于使用CompositeField,需手动将值写回record。
* materialid对应物料编号,model对应型号(列显示值)。
*/
editor.on("afteredit", function(editor, obj, record, rowIndex) {
record.set("materialid", editor.items.items[0].items.items[2].getValue());
record.set("model", editor.items.items[0].items.items[2].getRawValue());
}, this);
将RowEditor作为插件集成到GridPanel
定义GridPanel,并将editor作为插件传入。
{
xtype: "grid",
title: "产品BOM",
layout: "fit",
store: store,
enableDragDrop: false,
border: false,
frame: false,
autoScroll: true,
plugins: [editor],
sm: sm,
height: 340,
clicksToEdit: 2,
autoWidth: true,
viewConfig: { forceFit: true, autoFill: true, markDirty: false }
}
列定义与CompositeField实现
列定义中,物料名称/型号列使用CompositeField,包含三个ComboBox:品牌、类别、物料。通过change事件实现级联加载。
columns: [{
header: "物料名称/型号",
dataIndex: "model",
width: 200,
menuDisabled: true,
editor: {
xtype: "compositefield",
name: "compositefield",
items: [
{
xtype: "combo",
mode: "local",
name: "sets",
width: 80,
fieldLabel: "适用产品品牌",
emptyText: "请选择",
valueField: "id",
lazyInit: false,
value: this.data this.data.title : "",
hiddenName: "setid",
hiddenValue: this.data this.data.setid : "",
displayField: "title",
typeAhead: false,
forceSelection: true,
editable: true,
listeners: {
"change": function(combo, newvalue, oldvalue) {
var category = editor.items.items[0].items.items[1];
var material = editor.items.items[0].items.items[2];
var c = category.getValue();
var store = material.getStore();
store.load({
params: { setid: newvalue, category: c },
callback: function(r, options, success) {
if (success)
material.setValue("");
}
});
}
},
triggerAction: "all",
store: new Ext.data.JsonStore({
url: "<%=script_path%>data.asp",
root: "data",
autoDestroy: true,
remoteSort: true,
listeners: {
"load": function(store, records, option) {
var s = Ext.data.Record.create([{ name: "id", type: "int" }, { name: "title", type: "string" }]);
store.add(new s({ id: 0, title: "通用" }))
}
},
baseParams: { op: "setList" },
totalProperty: "total",
autoLoad: true,
fields: ["title", "id"]
})
},
{
xtype: "combo",
mode: "local",
width: 60,
name: "category",
fieldLabel: "类别",
emptyText: "请选择",
valueField: "category",
lazyInit: false,
value: this.data this.data.category : "",
displayField: "category",
typeAhead: false,
forceSelection: true,
triggerAction: "all",
listeners: {
"change": function(combo, newvalue, oldvalue) {
var sets = editor.items.items[0].items.items[0];
var material = editor.items.items[0].items.items[2];
var setid = sets.getValue();
var store = material.getStore();
store.load({
params: { category: newvalue, setid: setid },
callback: function(r, options, success) {
if (success)
material.setValue("");
}
});
}
},
store: new Ext.data.JsonStore({
url: "<%=script_path%>data.asp",
root: "data",
autoDestroy: true,
remoteSort: true,
baseParams: { op: "materialCategoryList" },
totalProperty: "total",
autoLoad: true,
fields: ["category"]
})
},
{
xtype: "combo",
forceSelection: true,
editable: true,
mode: "local",
name: "material",
fieldLabel: "物料",
emptyText: "请选择物料",
valueField: "id",
allowBlank: false,
displayField: "model",
width: 250,
lazyInit: false,
typeAhead: false,
triggerAction: "all",
listeners: {
"change": function(combo, newvalue, oldvalue) {
// 强制CompositeField值变化,使RowEditor能正确触发validateedit和afteredit
var comp = editor.items.items[0];
comp.setRawValue(combo.getRawValue());
}
},
store: new Ext.data.JsonStore({
url: "<%=script_path%>data.asp",
root: "data",
autoDestroy: true,
remoteSort: true,
baseParams: { op: "materialList" },
totalProperty: "total",
autoLoad: false,
fields: ["model", "id"]
})
}
]
}
},
{
header: "数量",
dataIndex: "qty",
width: 50,
menuDisabled: true,
editor: {
xtype: 'numberfield',
minValue: 1,
allowDecimals: false
}
},
{
header: "颜色",
dataIndex: "color",
width: 60,
menuDisabled: true
},
{
header: "尺寸",
dataIndex: "size",
width: 60,
menuDisabled: true
}]
谨以此记,分享给有需要的朋友。
