我有两个模型:Page和Department。我在extjs的列表视图中显示页面,我想在List视图中显示Department的Name而不是department_id。我没有得到实际将部门添加到页面VIA GUI的部分,只是通过直接的db insert语句,但我想至少能够在列表视图中显示部门名称。
到目前为止,我有以下内容,这是显示department_id
Ext.define('ExtMVC.model.Department', {
extend: 'Ext.data.Model',
fields: ['name']
});
Ext.define('ExtMVC.model.Page', {
extend: 'Ext.data.Model',
fields: ['title','body','department_id'],
associations: [
{type: 'belongsTo', model: 'Department'}
]
});
Ext.define('ExtMVC.store.Pages', {
extend: 'Ext.data.Store',
model: 'ExtMVC.model.Page',
autoLoad: true,
proxy: {
type: 'rest',
url: '/admin/pages',
format: 'json'
}
});
Ext.define('ExtMVC.store.Departments', {
extend: 'Ext.data.Store',
model: 'ExtMVC.model.Department',
autoLoad: true,
proxy: {
type: 'rest',
url: '/admin/departments',
format: 'json'
}
});
Ext.define('ExtMVC.view.page.List' ,{
extend: 'Ext.grid.Panel',
alias : 'widget.pagelist',
title : 'All Pages',
store: 'Pages',
initComponent: function() {
this.tbar = [{
text: 'Create Page', action: 'create'
}];
this.columns = [
{header: 'Title', dataIndex: 'title', flex: 1},
{header: 'Department', dataIndex: 'department_id', flex: 1}
];
this.callParent(arguments);
}
});
Ext.define('ExtMVC.controller.Pages', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'pagelist': {
itemdblclick: this.editPage
},
'pagelist > toolbar > button[action=create]': {
click: this.onCreatePage
},
'pageadd button[action=save]': {
click: this.doCreatePage
},
'pageedit button[action=save]': {
click: this.updatePage
}
});
},
onCreatePage: function () {
var view = Ext.widget('pageadd');
},
onPanelRendered: function() {
console.log('The panel was rendered');
},
doCreatePage: function (button) {
var win = button.up('window'),
form = win.down('form'),
values = form.getValues(),
store = this.getPagesStore();
if (form.getForm().isValid()) {
store.add(values);
win.close();
this.getPagesStore().sync();
}
},
updatePage: function (button) {
var win = button.up('window'),
form = win.down('form'),
record = form.getRecord(),
values = form.getValues(),
store = this.getPagesStore();
if (form.getForm().isValid()) {
record.set(values);
win.close();
this.getPagesStore().sync();
}
},
editPage: function(grid, record) {
var view = Ext.widget('pageedit');
view.down('form').loadRecord(record);
},
stores: [
'Pages',
'Departments'
],
models: [
'Page'
],
views: [
'page.List',
'page.Add',
'page.Edit'
]
});
答案 0 :(得分:9)
Ext的关联明显没有设计用于商店,而是用于处理单个记录......所以,我同意已经说过的话,你最好在服务器端压扁你的模型。然而,有可能实现你想要的。
在您调用生成的getter方法(即getDepartment()
)之前,关联不会加载您的关联模型(即Department)。试图采用这种方式,即为商店中加载的每个Page记录调用此方法需要大量的黑客攻击,因为网格会对商店的refresh
事件做出同步响应,而getDepartment()
方法返回异步 ...
这就是为什么您必须在加载页面的同一请求中加载部门数据的原因。也就是说,您的服务器必须返回以下格式的记录:
{title: 'First Page', body: 'Lorem', department_id: 1, department: {name: 'Foo'}}
为了让您的Page模型的代理服务于此,您需要以这种方式配置关联:
Ext.define('ExtMVC.model.Page', {
// ...
associations: [{
type: 'belongsTo'
// You need the fully qualified name of your associated model here
// ... which will prevent Ext from generating everything magically
,model: 'ExtMVC.model.Department'
// So you must also configure the getter/setter names (if you need them)
,getterName: 'getDepartment'
// Child data will be loaded from this node (in the parent's data)
,associationKey: 'department'
// Friendly name of the node in the associated data (would default to the FQ model name)
,name: 'department'
}]
});
然后是非常难看的部分。您的网格列无法使用经典dataIndex
属性访问关联数据。但是,如果已经加载了相关记录,则可以从TemplateColumn
这样访问:
{
header: 'Department'
,xtype: 'templatecolumn'
,tpl: '{department.name}'
}
不幸的是,这会阻止您使用一些您可能已全局配置的更合适的列类(日期列等)。此外,此列丢失了它所代表的模型字段的跟踪,这意味着基于内省的某些功能将无法发挥其魔力(例如,网格过滤器ux使用字段类型自动决定类型过滤器)。
但是在你暴露的特殊情况下,这无关紧要......
这是你把它们放在一起时所给出的东西(或see it in action)......
Ext.define('ExtMVC.model.Department', {
extend: 'Ext.data.Model',
fields: ['name'],
proxy: {
type: 'memory'
,reader: 'json'
,data: [
{id: 1, name: 'Foo'}
,{id: 2, name: 'Bar'}
,{id: 30, name: 'Baz'}
]
}
});
Ext.define('ExtMVC.model.Page', {
extend: 'Ext.data.Model',
fields: ['title','body','department_id'],
associations: [{
type: 'belongsTo'
,model: 'ExtMVC.model.Department'
,getterName: 'getDepartment'
,associationKey: 'department'
,name: 'department'
}],
proxy: {
type: 'memory'
,reader: 'json'
,data: [
{title: 'First Page', body: 'Lorem', department_id: 1, department: {name: 'Foo'}}
,{title: 'Second Page', department: {name: 'Bar'}}
,{title: 'Last Page', department: {name: 'Baz'}}
]
}
});
Ext.define('ExtMVC.store.Pages', {
extend: 'Ext.data.Store',
model: 'ExtMVC.model.Page',
autoLoad: true
});
Ext.define('ExtMVC.view.page.List', {
extend: 'Ext.grid.Panel',
alias : 'widget.pagelist',
title : 'All Pages',
store: Ext.create('ExtMVC.store.Pages'),
initComponent: function() {
this.tbar = [{
text: 'Create Page', action: 'create'
}];
this.columns = [
{header: 'Title', dataIndex: 'title', flex: 1}
,{header: 'Department', xtype: 'templatecolumn', flex: 1, tpl: '{department.name}'}
];
this.callParent(arguments);
}
});
Ext.widget('pagelist', {renderTo: 'ct', height: 200});
答案 1 :(得分:1)
正如其中一条评论所提到的,在处理网格/列表时将部门名称绑定到Pages模型会简单得多。显示的非规范化并不是一件坏事。
另一种选择可能是逆转建模,因为你可以说一个部门'hasMany'页面。
这允许您在关系上定义主键和外键,然后您的百货商店将(每行)有一个自动'pages()'商店,其中包含子信息。
我通常是为主/详细信息表单执行此操作,我想将'pages()'绑定到列表/网格,但是将部门模型保留为表单上的主记录。
答案 2 :(得分:0)
为什么不应该在网格列上使用渲染器配置功能?
这意味着在应用程序启动时(自动)加载部门存储(无论如何,您可能需要在更多地方使用它,将网格单元编辑器视为完整的部门列表)。
{
name:'Department',
dataIndex:'department_id',
renderer: function(deptId){
return Ext.data.StoreManager.lookup('Departments').getById(deptId).get('name');
}
}
PS:我正在使用自己的非规范化进行显示,但感觉并不好;)