The reason is that the customer has many types of materials, as many as a thousand. If only one Combobox is used, it will be difficult to quickly find a material in actual use. Therefore, I use two comboboxes containing material classification and material brand. Form a cascade filter. The problem lies precisely here. If you use multiple controls in a roweditor field, you must handle the initialization and Change event of each control. I haven't found anyone on the Internet with a good solution yet. After 3 days of debugging, I finally solved the problem and posted my code:
var editor=new Ext.ux.grid.RowEditor({
saveText: 'OK',
cancelText: "Give up",
commitChangesText: 'Please confirm or give up the changes' ,
errorText: 'Error'
});
//When canceling, delete empty records based on whether the value of the key field is empty
editor.on("canceledit",function (editor,pressed)
{
if(pressed && editor.record.get("materialid")==0)
{
store.remove(editor.record);
}
},this);
/*
afterstart This event is added by myself, because if you want to initialize your own control in the beforeedit event, it is impossible, because during beforeedit, the roweditor control is still There is no rendering, so I added the afterstart event, which is called immediately after the roweditor is displayed, so it can be initialized here.
It should be noted that the customized composite control
editor.items.items[0] is accessed by traversing through the roweditor control. It is not that I overwrote it here, but that the items of the roweditor control are not a collection. It is an object. I also spent some time here. Finally, I found that
editor.items.items[0] is the compositefield component through firebug output editor object. Through the items collection of this component, I can use the standard Access its subcomponents in the form. Next, you can initialize
Because the data of the last combobox is loaded through the first two combobox cascade selections, so load its data here for initialization, but pay attention , I executed it in the callback, because the load action of jsonstore is asynchronous, so the value must be initialized with setValue through the callback of the callback event after the data is loaded successfully
*/
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 event is executed when confirm is pressed and is used to verify each control in roweditor Value, here, I perform a custom validation action, because I don’t want users to be able to add duplicate materials, so I traverse the jsonstore and compare the material value of each record with the material value selected by the user. If found already exists, prompt the user not to add it repeatedly
*/
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("System prompt", "Do not add repeatedly");
store.remove(record);
}
return(!exist);
}, this);
/*
afterEdit is executed after passing verification. The most important action here is to assign values to certain attributes of the record being edited. The reason is that due to the use of compsitefield, roweditor cannot assign the selected To assign the correct attribute of the record, we need to manually assign the user's selection to the corresponding field. The materialid is the material number selected by the user, and the model corresponds to the model of the material
Why do we need to assign model? Because the model is the value of the column, if it is not assigned, the display will be empty
*/
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);
The above is the definition of roweditor and the processing of events. Next, insert roweditor as a plug-in into gridpanel
{
xtype:"grid",
title:"Product 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}
}
Next, let’s take a look at the column definitions of gridpanel. Here, you You can see how composite is used
columns: [{
header: "Material name/model",
dataIndex: "model",
width: 200,
menuDisabled: true,
editor:
{
//Definition editor
xtype: "compositefield",
name: "compositefield",
items:[
{
xtype: "combo ",
mode: "local",
name: "sets",
width:80,
fieldLabel: "Applicable product brands",
emptyText: "Please select",
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)
{
//Handle the brand's change event. After selecting the brand, reload the combobox. The editor is an instance of the roweditor defined previously
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:"Universal"}))
}},
baseParams: {op: "setList" },
totalProperty: "total",
autoLoad: true,
fields: ["title","id"]
})
},
{
xtype: "combo",
mode:"local",width:60,
name:"category",
fieldLabel: "category",
emptyText:"Please select",
valueField: "category",
lazyInit:false,
value:this.data?this.data.category:"",
displayField: "category",
typeAhead: false,forceSelection : true,
triggerAction: "all",
listeners:{
"change":function(combo,newvalue,oldvalue)
{
//Handle the change event of the category, after selecting After branding, reload combobox. Editor is an instance of roweditor defined previously
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: "material",
emptyText:"Please select a material",
valueField: "id",
allowBlank:false,
displayField: "model",
width:250,
lazyInit:false,
typeAhead: false,
triggerAction: "all",
listeners:{
"change" :function(combo,newvalue,oldvalue)
{
//Be sure to pay attention here! ! ! If there are no two sentences below, you will find that the displayed value will not change after you select it, and it cannot be updated even if you click Confirm. Why? Because roweditor determines whether to call validateedito and afteredit by detecting the isdirty attribute of the record, it determines whether the control value corresponding to each column changes. Since the material model column corresponds to compositefield, we must let When the compositefield value changes, roweditor will call validedit and afteredit, and the compositefield value will also be called to display in the column
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: "quantity",
dataIndex: "qty",
width: 50,
menuDisabled: true,
editor: {
xtype: 'numberfield',
minValue:1,
allowDecimals:false
}
}
,{
header: "color",
dataIndex: "color",
width: 60,
menuDisabled : true
}
,{
header: "size",
dataIndex: "size",
width: 60,
menuDisabled: true
}
]
}
]
I would like to take this note and share it with friends in need.