用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
                
            }
            
            ]

        
                  }
                                            
               
                    ]
        

 谨以此记,分享给有需要的朋友