extjs列表视图中的模型关联

jdk*_*aly 9 extjs extjs4 extjs-mvc

我有两个模型: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'}
    ]
});
Run Code Online (Sandbox Code Playgroud)

商店

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'
    }
});
Run Code Online (Sandbox Code Playgroud)

列表显示

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);
    }
});
Run Code Online (Sandbox Code Playgroud)

控制器(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'
    ]
});
Run Code Online (Sandbox Code Playgroud)

rix*_*ixo 9

Ext的关联明显没有设计用于商店,而是用于处理单个记录......所以,我同意已经说过的话,你最好在服务器端压扁你的模型.然而,有可能实现你想要的.

在您调用生成的getter方法(即getDepartment())之前,关联不会加载您的关联模型(即Department ).尝试这种方式,即为商店中加载的每个Page记录调用此方法将需要大量的黑客攻击,因为网格同步响应refresh商店的事件,而该getDepartment()方法异步返回...

这就是为什么您必须在加载页面的同一请求中加载部门数据的原因.也就是说,您的服务器必须返回表单的记录:

{title: 'First Page', body: 'Lorem', department_id: 1, department: {name: 'Foo'}}
Run Code Online (Sandbox Code Playgroud)

为了使您的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'
    }]
});
Run Code Online (Sandbox Code Playgroud)

然后是真正丑陋的部分.您的网格列无法使用classic dataIndex属性访问关联数据.但是,如果已经加载了相关的记录,可以通过以下方式访问TemplateColumn:

{
    header: 'Department'
    ,xtype: 'templatecolumn'
    ,tpl: '{department.name}'
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这将阻止您使用一些您可能已全局配置的更合适的列类(日期列等).此外,此列丢失了它所代表的模型字段的跟踪,这意味着基于内省的某些功能将无法发挥其魔力(例如,网格过滤器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});
Run Code Online (Sandbox Code Playgroud)