【问题标题】:extjs model associations in a list view列表视图中的 extjs 模型关联
【发布时间】:2013-02-21 16:17:00
【问题描述】:

我有两个模型:Page 和 Department。我在 extjs 的列表视图中显示页面,我想在列表视图中显示部门名称而不是部门 ID。我还没有真正通过 GUI 将部门添加到页面中,只能通过直接 db insert 语句,但我希望至少能够在列表视图中显示部门名称。

到目前为止,我有以下内容,这是显示部门 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'
    ]
});

【问题讨论】:

  • 我只需将部门名称与页面记录一起带入并将其映射到模型中,以便我可以在网格中使用它。
  • 排序这个有什么乐趣吗?我自己也遇到了类似的问题......

标签: extjs extjs4 extjs-mvc


【解决方案1】:

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

在您调用生成的 getter 方法(即getDepartment())之前,该关联不会加载您的关联模型(即部门)。尝试采用这种方式,即为商店中加载的每条 Page 记录调用此方法将需要大量的 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 使用字段类型来自动决定过滤器)。

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

完整示例

这就是当你把它们放在一起(或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});

【讨论】:

  • 你能举一个getDepartment函数的例子吗?
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-17
      • 1970-01-01
      • 2013-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-01
      • 2013-03-05
      相关资源
      最近更新 更多