9

我有两个模型:页面和部门。我在 extjs 的列表视图中显示页面,我想在列表视图中显示部门名称而不是部门 ID。我还没有真正通过 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);
    }
});

控制器 (fwiw)

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'
    ]
});
4

3 回答 3

9

Ext 的关联显然不是为在商店中使用而设计的,而是为处理单个记录而设计的……所以,我同意已经说过的,你最好在服务器端扁平化你的模型。尽管如此,有可能实现您想要的。

在您调用生成的 getter 方法(即)之前,该关联不会加载您的关联模型(即 Department getDepartment())。尝试采用这种方式,即为商店中加载的每个页面记录调用此方法将需要大量的 hack,因为网格对商店的事件同步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 使用字段类型来自动决定筛选)。

但是在您暴露的特定情况下,这无关紧要...

完整示例

当你把它们放在一起(或看到它在行动中)时,它会给出什么......

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});
于 2013-05-17T19:07:31.537 回答
1

正如其中一条评论所提到的,在使用网格/列表时,将部门名称绑定到 Pages 模型会简单得多。显示的非规范化并不是一件坏事。

另一种选择可能是反转建模,因为您可以说一个部门“有很多”页面。

这允许您在关系上定义主键和外键,然后您的百货商店将(每行)有一个自动的“pages()”存储,其中将包含子信息。

我通常为我想将“pages()”绑定到列表/网格的主/详细表单执行此操作,但例如将部门模型保留为表单上的主记录。

于 2013-05-17T14:06:00.350 回答
0

为什么不应该在网格的列上使用渲染器配置功能?

这意味着在应用程序启动时预先(自动)加载部门存储(无论如何,您可能在更多地方需要它,将网格单元编辑器视为完整的部门列表)。

{
  name:'Department',
  dataIndex:'department_id',
  renderer: function(deptId){
    return Ext.data.StoreManager.lookup('Departments').getById(deptId).get('name');
  }
}

PS:我正在使用自己的非规范化进行显示,但感觉不太好;)

于 2014-09-27T11:27:53.993 回答