用RowEditor作批量编辑器时,遇到一个问题,想要在Roweditor中使用三个下拉列表组成级联式选择控件,原因是客户的物料种类非常多,有一千种之多,如果单纯用一个Combobox,那么在实际使用中,很难快速找到一个物料,所以,我使用包含物料分类和物料品牌的两个combobox来组成级联式筛选。问题恰恰出在这儿,如果在roweditor的一个字段中用多个控件,就要处理每个控件的初始化,Change事件。网上目前还未找到有人有好的解决办法。经过3天的调试,我终于解决了问题,把我的代码贴出来:
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 这个事件是自己加的,因为如果在beforeedit事件中想对自己的控件初始化,那是不可能的,因为beforeedit时,roweditor控件还没有渲染,所以,我加了afterstart事件,该事件在roweditor显示后立即调用,所以,可以在这里进行初始化。
要注意的是通过roweditor控件进行遍历来访问自定义的composite控件
editor.items.items[0],这里并不是我写重了,而是roweditor控件的items竟然不是一个集合,而是一个对象,在这里我也耗了一些时间,最后还是通过firebug输出editor对象发现的
editor.items.items[0]就是compositefield组件,通过该组件的items集合,就可以以标准的形式访问其子组件,接下来,就可以初始化了
因为最后一个combobox的数据是要通过前两个combobox级联选取后载入的,所以,在这里载入其数据进行初始化,但是注意,我是在callback中执行的,因为jsonstore的load动作是异步的,所以,必须通过callback事件的回调在数据载入成功后,再用setValue来初始化值
*/
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事件是在按了确认时执行的,用来验证roweditor中各控件的值,在这里,我执行了一个自定义的验证动作,因为我不想用户可以添加重复的物料,所以,我通过遍历jsonstore,将每条记录的物料值与用户选择的物料值进行比较,如果发现已经存在,则提示用户不要重复加入
*/
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是通过验证后执行的,这里最重要的动作是将正在编辑的记录的某些属性赋值,原因是由于采用了compsitefield,所以,roweditor无法将选取的值赋给record的正确属性,需要我们手工将用户的选择赋给相应的字段,materialid就是用户选的物料编号,而model对应是该物料的型号
为什么要赋model呢?因为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的定义和对事件的处理,接下来,将roweditor作为插件插入到gridpanel
{
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
}
}
接下来,再看看关于gridpanel的列定义,这里,你可以看到composite是如何用的
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)
{
//
处理品牌的change事件,在选取品牌后,重新载入combobox,editor就是前文定义的roweditor的实例
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)
{
//
处理类别的change事件,在选取品牌后,重新载入combobox,editor就是前文定义的roweditor的实例
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)
{
//
这里一定要注意!!!如果没有下面这两句,那你选择后,会发现显示的值不会变化,并且,点了确认,也不能更新。为什么呢?因为roweditor是通过检测record的isdirty属性来决定是不是调用validateedito和afteredit的,它是检测每列对应的控件值是否变化来判断的,由于物料型号这列,对应的是compositefield,所以,我们必须让compositefield值发生变化,roweditor才会调用validedit和afteredit,并且,compositefield的值还会被调用来显示在列里
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
}
]
}
]
谨以此记,分享给有需要的朋友