Retrieve GridPanel model/store/columns dynamically

2020-03-04 07:51发布

I have a GridPanel that must have its store model AND column model created dynamically, after a DB SP returns the columns of the table.

My question is how can I pass the value ( string or JSON )s from the server to the GridPanel?

Ext.define('Base.GridPanel', {
    extend: 'Ext.grid.Panel',
    xtype: 'gridpanel',

    flex: @BFE.Frontend.Defaults.BaseGridPanel.flex,
    hideMode: '@BFE.Frontend.Defaults.BaseGridPanel.hideMode',

    collapsible: true,

    constructor: function(id, title, columns, store) 
    {
        this.id = id;
        this.title = title;
        this.columns = columns;
        this.store = store;

        this.callParent();
    }
});

I use this custom defined GridPanel along with the following model and store for now.

Ext.define('Tasks', {
    extend: 'Ext.data.Model',

    fields: 
    [
        {name: 'Case_ID', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'BP_Name', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Project', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Business_Unit', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Task', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Title', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Last_Edit', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Entity_Name', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Process_Instance_ID', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Start_of_Business', type: '@MCSJS.Models.DataType.Auto'},
        {name: 'Last_User', type: '@MCSJS.Models.DataType.Auto'}
    ]
});

var myTaskStore = Ext.create('Ext.data.Store', {
    storeId: 'myTasks',
    model: 'Tasks',
    autoLoad: true,
    proxy:  
    {
        type: 'ajax',
        url: '/Task/GetMyTaskData',
        reader: 
        {
            type: 'json',
            root: 'data'
        }
    }
});

This is how I create a GridPanel :

var columns = [ { text: 'Case ID', dataIndex: 'Case_ID' },
                { text: 'BP Name', dataIndex: 'BP_Name' } ];
new Base.GridPanel('@BFE.Frontend.MyTask.GridPanel', 'My Tasks', columns, myTaskStore)

标签: c# Extjs extjs4
1条回答
男人必须洒脱
2楼-- · 2020-03-04 08:15

Ext provides some support for that. You can send the model configuration by adding a metaData property to the server response. You can configure the name of the property with the metaProperty option.

The documentation doesn't make it obvious, but you can reconfigure the fields of the model this way. Here's the kind of response that would do that:

{
    data: [...]

    ,metaData: {
        // This will be recognized and processed automatically
        // by the proxy
        fields: [
            {name: "id", type: "int"},
            {name: "myField", type: "string"},
            ...
        ]

        // This one is for our own usage, see bellow
        ,columns: [
            {dataIndex: "id", text: "ID},
            {dataIndex: "myField", text: "My field"},
            ...
        ]
    }
}

As noted in the doc, when the data model changes, you'll want to update your components as well. Sencha has provided the metachange for that. Notice that, while documented in the proxy, this event will be relayed by the store.

Finally, to update the grid's column model, you have the reconfigure method. For example, you could modify your grid class in the following way to make it reconfigure itself automatically from the server response:

Ext.define('Base.GridPanel', {
    extend: 'Ext.grid.Panel'

    // ...

    // You can add your listener in initComponent, if you're
    // reluctant to extend a method docuemented as private...
    ,bindStore: function(store) {

        // unbind previously bind store, if any
        var previous = this.getStore();
        if (previous) {
            previous.un('metachange', this.onMetaChange, this);
        }

        // bind to the meta change event
        this.getStore().on('metachange', this.onMetaChange, this);

        this.callParent(arguments);
    }

    ,onMetaChange: function(store, meta) {
        var columns = meta.columns;
        if (columns) {
            this.reconfigure(null, columns);
        }
    }
});

Update

The onMetaChange method is called when the metachange event is fired, because I have registered it as a listener with this line:

this.getStore().on('metachange', this.onMetaChange, this);

The event itself is fired when the proxy detects some meta data in the server response. Concretely, that happens when a metaData property (or whatever name you may have configured as the metaProperty of the proxy) exists in the server response.

The listener is effectively passed the raw metaData object, that is present in the response, as its second argument (named meta in my example). So your server can put any information you need in it (e.g. new field labels, tooltip texts, etc.).

bindStore is a method that is already present in GridPanel. Here I override it because I need a place to register my event listener on the store. As its name suggests, this method is called to bind a store to the component. It can be the initial store, or a new one. That's one I've preferred to override this method instead of initComponent. In case the store is changed later in the component life, my custom listener will be unbound from the old store and attached to the new one.

The arguments keyword is an idiosyncrasy of Javascript. It represents all the arguments that have been passed to a function. callParent is a sweety provided by Ext to call the parent method; it takes an array as the arguments that will be passed to the parent. So this.callParent(arguments) calls the parent method without having to know what were precisely all the arguments of the overridden method. That's easier, and that's also more resilient to future changes, if the arguments of the method were to change...

I'd be glad to point you to a comprehensive guide about overriding in Ext... Unfortunately I couldn't find one with a quick search :-/

查看更多
登录 后发表回答