今天项目遇到一个问题,需要使用extjs4 的grid的动态列,即列表的列需要根据需要动态的生成。
思路:定义grid时,columns根据配置获取,store中model的fields也根据配置动态获取。但是发现store中model的fields是很难改变的,因为很难拿到model对象,来执行model.setFields()方法。经过查看AbstractStore的源码发现,extjs4为了兼容extjs3当store中不给配置model属性,而配置了fields属性的时候,store会默认生成一个ImplicitModel。所以要实现动态的列,只需给store配置动态proxy(对应不同的url)、和动态的fields即可。
(只需关注标红的代码和添加了注释的代码即可,其它的代码是方便我日后参考)
AbstractStore生成自定义model的代码如下:
//Supports the 3.x style of simply passing an array of fields to the store, implicitly creating a model
if (!me.model && me.fields) {
me.model = Ext.define('Ext.data.Store.ImplicitModel-' + (me.storeId || Ext.id()), {
extend: 'Ext.data.Model',
fields: me.fields,
proxy: me.proxy || me.defaultProxyType
});
delete me.fields;
me.implicitModel = true;
}
定义的store代码如下:
Ext.define('shinow.ux.drugSearch.DrugSearchComboStore', {
extend : 'Ext.data.Store',
constructor : function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({}, cfg)]);
}
});
定义的combobox的代码如下:
Ext.require('shinow.shinow.ux.field.GridComboBox');
Ext.define('shinow.ux.drugSearch.DrugSearchCombo', {
extend : 'shinow.ux.field.GridComboBox' ,
requires : ['shinow.shinow.ux.drugSearch.DrugSearchComboStore'],
alias : 'widget.drugSearchCombo',
constructor : function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([
Ext.apply({
contentWidth : 500,
contentHeight : 400,
pageSize : 15,
queryMode : 'remote',
minChars : 2
},cfg)
]);
}
,
initComponent : function() {
var me = this;
var proxy = {
type : 'ajax',
url : me.url,//动态配置url
actionMethods : {
create : "POST",
read : "POST",
update : "POST",
destroy : "POST"
},
reader : {
type : 'json',
root : 'resultData.data',
totalProperty : 'resultData.totalProperty'
}
};
if(me.url && me.fields) {
//此处将动态的配置信息传入store中,实现动态列。proxy提供数据源,fields实现表格的列
me.store = Ext.create('shinow.ux.drugSearch.DrugSearchComboStore',{proxy : proxy ,fields : me.fields});
}else {
Ext.Msg.alert('警告','请配置控件的url和fields属性!');
}
me.callParent(arguments);
}
});
下拉grid GridComboBox 代码如下:
Ext.define("shinow.ux.field.GridComboBox", {
extend: "Ext.form.field.ComboBox",
alias: ["widget.gridcombobox", "widget.gcombobox", "widget.gcombo"],
requires: ["shinow.shinow.ux.grid.GridList", "shinow.shinow.ux.grid.GridListKeyNav"],
contentWidth: 400,
contentHeight: 400,
queryCaching: false,
matchFieldWidth: false,
initComponent: function() {
var a = this;
if (!a.queryMode || a.queryMode == "remote") {
if (!a.triggerAction || a.triggerAction == "all") {
a.triggerAction = "query"
}
}
a.callParent()
},
onmouseupEvn: function(c, b, a) {
c.stopEvent();
if (this.editable) {
this.inputEl.focus()
}
},
createPicker: function() {
var c = this;
var d = [{
xtype: "rownumberer",
resizable: true
}];
if (c.columns) {
d = d.concat(c.columns)
}
if (!c.listConfig) {
c.listConfig = {}
}
c.listConfig.columns = d;
var b, a = Ext.apply({
xtype: "gridlist",
pickerField: c,
selModel: {
mode: c.multiSelect ? "SIMPLE" : "SINGLE"
},
border: false,
height: c.contentHeight,
width: c.contentWidth,
cls: "x-boundlist",
floating: true,
hidden: true,
store: c.store,
displayField: c.displayField,
focusOnToFront: false,
pageSize: c.pageSize
}, c.listConfig, c.defaultListConfig);
b = c.picker = Ext.widget(a);
if (c.pageSize) {
b.pagingToolbar.on("beforechange", c.onPageChange, c)
}
c.mon(b, {
itemclick: c.onItemClick,
refresh: c.onListRefresh,
scope: c
});
c.mon(b.getSelectionModel(), {
beforeselect: c.onBeforeSelect,
beforedeselect: c.onBeforeDeselect,
selectionchange: c.onListSelectionChange,
scope: c
});
var h = c.valueModels || [],
g = h.length,
i, f;
var e = [];
for (i = 0; i < g; i++) {
f = h[i];
if (f && f.isModel && c.store.indexOf(f) >= 0) {
e.push(f)
}
}
if (e.length) {
b.show();
b.getView().getSelectionModel().select(e, undefined, true)
}
c.mon(c.inputEl, "mousedown", c.onmouseupEvn, c);
return b
},
getSelMode: function() {
return this.valueModels
},
onExpand: function() {
var d = this,
a = d.listKeyNav,
c = d.selectOnTab,
b = d.getPicker();
if (a) {
a.enable()
} else {
a = d.listKeyNav = new shinow.ux.grid.GridListKeyNav(this.inputEl, {
gridList: b,
forceKeyDown: true,
tab: function(f) {
if (c) {
this.selectHighlighted(f);
d.triggerBlur()
}
return true
},
enter: function(h) {
var f = b.getSelectionModel(),
g = f.getCount();
this.selectHighlighted(h);
if (!d.multiSelect && g === f.getCount()) {
d.collapse()
}
}
})
}
if (c) {
d.ignoreMonitorTab = true
}
Ext.defer(a.enable, 1, a);
d.inputEl.focus()
},
doAutoSelect: function() {
var b = this,
a = b.picker,
c, d;
if (a && b.autoSelect && b.store.getCount() > 0) {
c = a.getSelectionModel().lastSelected;
d = a.getView().getNode(c || 0);
if (d) {
a.getView().highlightItem(d);
a.getView().getTargetEl().scrollChildIntoView(d, false)
}
}
},
alignPicker: function() {
var b = this,
a = b.getPicker();
if (b.isExpanded) {
if (b.matchFieldWidth) {
a.setWidth(b.bodyEl.getWidth())
}
if (a.isFloating()) {
b.doAlign()
}
}
},
onTriggerClick: function() {
var a = this;
if (!a.readOnly && !a.disabled) {
if (a.isExpanded) {
a.collapse()
} else {
a.onFocus({});
if (a.triggerAction === "all") {
a.doQuery(a.allQuery, true)
} else {
if (a.triggerAction === "last") {
a.doQuery(a.lastQuery, true)
} else {
a.doQuery(a.getRawValue(), true, true)
}
}
}
a.inputEl.focus()
}
},
doRemoteQuery: function(b) {
var c = this,
a = function() {
c.afterQuery(b)
};
if (c.pageSize) {
c.loadPage(1, {
rawQuery: b.rawQuery,
callback: a
})
} else {
c.store.load({
params: c.getParams(b.query),
rawQuery: b.rawQuery,
callback: a
})
}
c.expand()
}
});
GridList代码如下:
Ext.define("shinow.ux.grid.GridList", {
extend: "Ext.panel.Table",
requires: ["Ext.grid.View"],
alias: ["widget.gridlist"],
alternateClassName: ["Ext.list.ListView", "Ext.ListView", "Ext.grid.GridPanel"],
viewType: "gridview",
lockable: false,
rowLines: true,
deferRowRender: false,
columnLines: true,
initComponent: function() {
var a = this;
a.callParent();
if (a.pageSize) {
a.pagingToolbar = a.createPagingToolbar();
a.addDocked(a.pagingToolbar)
}
},
createPagingToolbar: function() {
return Ext.widget("pagingtoolbar", {
id: this.id + "-paging-toolbar",
pageSize: this.pageSize,
store: this.store,
dock: "bottom",
displayInfo: true,
border: false,
ownerCt: this,
ownerLayout: this.getComponentLayout()
})
}
});
GridListKeyNav代码如下:
Ext.define("shinow.ux.grid.GridListKeyNav", {
extend: "Ext.util.KeyNav",
requires: "shinow.shinow.ux.grid.GridList",
constructor: function(b, a) {
var c = this;
c.gridList = a.gridList;
c.callParent([b, Ext.apply({}, a, c.defaultHandlers)])
},
defaultHandlers: {
up: function() {
var e = this,
b = e.gridList,
d = b.getView().all,
f = b.getView().highlightedItem,
c = f ? b.getView().indexOf(f) : -1,
a = c > 0 ? c - 1 : d.getCount() - 1;
e.highlightAt(a)
},
down: function() {
var e = this,
b = e.gridList,
d = b.getView().all,
f = b.getView().highlightedItem,
c = f ? b.getView().indexOf(f) : -1,
a = c < d.getCount() - 1 ? c + 1 : 0;
e.highlightAt(a)
},
pageup: function() {},
pagedown: function() {},
home: function() {
this.highlightAt(0)
},
end: function() {
var a = this;
a.highlightAt(a.gridList.all.getCount() - 1)
},
enter: function(a) {
this.selectHighlighted(a)
}
},
highlightAt: function(a) {
var b = this.gridList,
c = b.getView().all.item(a);
if (c) {
c = c.dom;
b.getView().highlightItem(c);
b.getView().getTargetEl().scrollChildIntoView(c, false)
}
},
selectHighlighted: function(f) {
var d = this,
b = d.gridList,
c = b.getView().highlightedItem,
a = b.getSelectionModel();
if (c) {
a.selectWithEvent(b.getView().getRecord(c), f)
}
}
});
引用下拉列表的代码如下:\\这段代码就是如何使用自己定义的下拉列表类
{
xtype : 'drugSearchCombo',
fieldLabel :'药品查询',
labelAlign : 'right',
contentWidth : 500,
contentHeight : 400,
width : 200,
pageSize : 15,
queryMode : 'remote',
minChars : 2,
url : contentPath + '/chargeItem/queryChargeItemList.action',//动态配置url数据源地址
fields : [//动态配置fields决定列表的列
{
//收费项目ID
name : 'feeInfoID'
}
,{
//收费项目类型ID
name : 'feeTypeID'
}
,{
//收费项目分类(主键ID)
name : 'feeKindID'
}
,{
//收费项目编码
name : 'feeInfoCode'
}
,{
//收费项目名称
name : 'feeInfoName'
}
],
columns : [//动态配置列表的列
{
text : '收费项目ID',
dataIndex : 'feeInfoID',
flex : 1
}
,{
text : '收费项目类型ID',
dataIndex : 'feeTypeID',
flex : 1
}
,{
text : '收费项目分类',
dataIndex : 'feeKindID',
flex : 1
}
,{
text : '收费项目编码',
dataIndex : 'feeInfoCode',
flex : 1
}
,{
text : '收费项目名称',
dataIndex : 'feeInfoName',
flex : 1
}
]
}
注意:使用需要在view中,通过requires方式,将控件引入
requires : ['shinow.shinow.ux.drugSearch.DrugSearchCombo']