1.嵌套模型(nested model)
在model中使用hasmany可以定义父子结构的嵌套模型,举一个实际的例子:Chart模型中包含坐标轴YAxis,Cell,Serie和PolyLine四个子模型,代码如下所示,hasmany定义了父子关系,当我们得到一个chart实例时,可以通过chart.Cells()得到以Cell为model的store。
Ext.define('Arim.model.chart.Chart', {
extend: 'Arim.model.Base',
requires: [
'Arim.model.chart.PlotLine',
'Arim.model.chart.Cell',
'Arim.model.chart.Serie',
'Arim.model.chart.YAxis'
],
fields: [
{ name: 'Name', type: 'string' },
{ name: 'Group', type: 'string' },
{ name: 'Inter', type: 'int' },
{ name: 'Categories', type: 'string' }
],
idProperty: 'Name',
proxy: {
type: 'memory',
reader: {
type: 'json'
},
writer: new Ext.data.JsonWriter({
getRecordData: function (record) {
Ext.apply(record.data, record.getAssociatedData());
return record.data;
}
})
},
hasMany: [
{ model: 'Arim.model.chart.PlotLine', name: 'PlotLines', associationKey:'PlotLines' },
{ model: 'Arim.model.chart.Cell', name: 'Cells', associationKey:'Cells' },
{ model: 'Arim.model.chart.Serie', name: 'Series', associationKey:'Series' },
{ model: 'Arim.model.chart.YAxis', name: 'YAxises', associationKey:'YAxises' }
]
});
Ext.define('Arim.model.chart.PlotLine', {
extend: 'Arim.model.Base',
fields: [
{name:'Axis',type:'string'},
{name:'Color', type:'string'},
{name:'DashStyle', type:'string'},
{name:'Id', type:'int'},
{name:'Value',type:'int'},
{name:'Label',type:'string'},
{name:'Width',type:'int'},
{name:'zIndex', type:'int'}],
idProperty:'Id'
});
Ext.define('Arim.model.chart.Cell', {
extend: 'Arim.model.Base',
fields: [
{name:'Name', type:'string'},
{name:'PropertyId', type:'int'},//属性id
{name:'TagId', type:'int'},//标签id
{name:'Act',type:'int'},
{name:'Offset',type:'int'},
{name:'Inter',type:'int'},
{name:'Unit', type:'string'},
{name:'Data', type:'float'},
{name:'InterCount', type:'int'},
{name:'Fun',type:'string'}],
idProperty:'Name'
});
Ext.define('Arim.model.chart.Serie', {
extend: 'Arim.model.Base',
fields: [
{name:'Name', type:'string'},
{name:'Type', type:'string', defaultValue:'曲线'},
{name:'ShowInLegend', type:'boolean', defaultValue:true},
{name:'YAxis', type:'int', defaultValue:0},
{name:'X', type:'string'},
{name:'Y'},
{name:'Z'},
{name:'Used', type:'boolean', defaultValue:false},
{name:'stack',type:'string'}],
idProperty:'Name'
});
2.嵌套模型的编辑
有了父子结构,我们可以设计一个form,里下包含多个grid,每个子模型关联一个grid,用来编辑Chart,对于Chart的属性可以用form.loadRecord(chart)加载,对于子模型则可以用grid.reconfigure(chart.Cells())加载。修改完成后,可以通过form.updateRecord(chart)得到修改后的chart,将chart提交到后台。form的设计代码如下。
Ext.define('Arim.view.chart.Template', {
extend: 'Ext.form.Panel',
alias: 'widget.charttemplate',
requires: [
'Arim.model.chart.Chart',
'Arim.view.chart.config.Cells',
'Arim.view.chart.config.PlotLine',
'Arim.view.chart.config.Series',
'Arim.view.chart.config.YAxis',
'Arim.view.chart.TemplateController'
],
autoScroll: true,
controller: 'charttemplate',
create: true,
template: {},
bodyPadding: 10,
closable: true,
layout: {
type: 'vbox',
defaultMargins: '5,0,0,0',
align: 'stretch'
},
items: [{
xtype: 'fieldset',
layout: 'hbox',
items: [{
xtype: 'textfield',
fieldLabel: '标题',
labelAlign: 'right',
name: 'Name',
itemId: 'name',
flex:4
}, {
xtype: 'textfield',
fieldLabel: '分组',
labelAlign: 'right',
name: 'Group',
itemId: 'group',
flex:3
}, {
xtype: 'combobox',
hideLabel: true,
queryMode: 'local',
store: 'ChartIntertype',
displayField: 'Text',
valueField: 'Value',
itemId: 'inter',
name:'Inter',
value: 86400,
editable: false
}, {
icon: 'resources/icons/spline.png',
xtype: 'splitbutton',
itemId: 'serie',
text: '曲线',
enableToggle: true,
listeners: {
toggle: 'seriebtntoggle'
},
menu: {
itemId: 'serietypemenu',
items: [
{ icon: 'resources/icons/spline.png', 'text': '曲线', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/pie.png', 'text': '饼图', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/column.png', 'text': '柱状图', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/stackcolumn.png', 'text': '叠加柱状图', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/area3d.png', 'text': '面积图', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/stackarea.png', 'text': '叠加面积图', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/scatter.png', 'text': '散点图', handler: 'seriebtnmenuclick' },
{ icon: 'resources/icons/bubble.png', 'text': '气泡图', handler: 'seriebtnmenuclick' }
]
},
flex:1
}]
}, {
xtype: 'textfield',
fieldLabel: 'x轴类别',
labelAlign: 'right',
name: 'Categories',
itemId: 'categories'
}, {
xtype: 'chartyaxis',
itemId: 'yaxisgrid',
name: 'YAxises'
}, {
xtype: 'chartplotLine',
itemId: 'plotlinegrid',
name: 'PlotLine'
}, {
xtype: 'chartseries',
itemId: 'seriesgrid',
name: 'Series'
}, {
xtype: 'chartcells',
itemId: 'cellsgrid',
name: 'Cells'
}],
buttons: [{
text: '保存',
itemId: 'submit',
handler: 'acceptChange'
}],
listeners: {
afterrender: 'afterrender',
destroy: 'destroy'
}
});
3.将嵌套模型encode得到json字符串
当使用嵌套模型(nested model)时,通过proxy直接向后台提交可以将模型的层次化json保存,load时也可以将后台返回的json构建出嵌套模型实例,这其中的工作是由proxy里面的reader, writer完成的。如果要把嵌套模型在前端encode得到字符串则只有父级的属性保存,子集信息丢失,decode时也得不到子集信息。
因此,需要调用Chart里面proxy的writer来得到嵌套模型的json:
var writer = Arim.model.chart.Chart.getProxy().getWriter();
var data = writer.getRecordData(chartmodel);
var json = Ext.encode(data);
读取时需要调用Chart里面proxy的reader来解析json得到嵌套模型:
var reader = Arim.model.chart.Chart.getProxy().getReader();
var model = reader.readRecords([json]).getRecords()[0];
4.总结
嵌套模型对于处理复杂业务对象很有用处,我们在生产中会把图形(本文中的例子)、报表等设计为模板,模板再encode为json字符串保存到后台,采用嵌套模型和相应的form代码逻辑简单清晰,通过reader、writer实现嵌套模型与json字符串之间的转换是其中的关键。