9

ページと部門の 2 つのモデルがあります。extjs のリスト ビューでページを表示しています。リスト ビューに department_id の代わりに Department's Name を表示したいと思います。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()。このように行おうとすると、ストアにロードされた各ページ レコードに対してこのメ​​ソッドを呼び出すには、信じられないほどの量のハックが必要になります。これは、グリッドがストアのイベントに同期的に反応し、メソッドが非同期に戻るためです...refreshgetDepartment()

そのため、ページをロードする同じリクエストで部門データをロードする必要があります。つまり、サーバーは次の形式のレコードを返す必要があります。

{title: 'First Page', body: 'Lorem', department_id: 1, department: {name: 'Foo'}}

ページ モデルのプロキシがこれを使用するには、関連付けを次のように構成する必要があります。

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 に答える
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 に答える