EXT JS 4 use an model association to render a grid display value

巧了我就是萌 提交于 2020-01-01 05:31:07

问题


Details

I have a grid used to display invoice information. The grid is populated using the Invoice store, the Invoice store uses the Invoice model, the Invoice model has a "has one" association with the InvoiceStatus model with a primary key of 'id' and a foren key of 'invoice_status_id'.

Problem

I'm not sure how to make the display value of the Invoice Grid's 'Status' column use the associated models 'name' inserted of the invoice_status_id. I know I need to create a renderer to do this however I still get a null value. Both the Invoice and InvoiceStatus stors are populating with the correct values.

Status Column Render

renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
    return record.getStatus().get('name');
},

Invoice Store

Ext.define('MyApp.store.Invoice', {
    extend: 'Ext.data.Store',

    requires: [
        'MyApp.model.InvoiceModel'
    ],

    constructor: function(cfg) {
        var me = this;
        cfg = cfg || {};
        me.callParent([Ext.apply({
            autoLoad: true,
            autoSync: true,
            model: 'MyApp.model.InvoiceModel',
            remoteSort: true,
            storeId: 'StoreInvoce',
            proxy: {
                type: 'rest',
                url: '/api/invoice',
                reader: {
                    type: 'json',
                    root: 'data'
                }
            }
        }, cfg)]);
    }
});

InvoiceStatus Store

Ext.define('MyApp.store.InvoiceStatus', {
    extend: 'Ext.data.Store',
    alias: 'store.InvoiceStatus',

    requires: [
        'MyApp.model.InvoiceStatus'
    ],

    constructor: function(cfg) {
        var me = this;
        cfg = cfg || {};
        me.callParent([Ext.apply({
            autoLoad: true,
            autoSync: true,
            model: 'MyApp.model.InvoiceStatus',
            remoteSort: true,
            storeId: 'MyJsonStore1',
            proxy: {
                type: 'rest',
                url: '/api/invoice_status',
                reader: {
                    type: 'json',
                    root: 'data'
                }
            }
        }, cfg)]);
    }
});

Invoice Model

Ext.define('MyApp.model.InvoiceModel', {
    extend: 'Ext.data.Model',

    uses: [
        'MyApp.model.InvoiceStatus'
    ],

    fields: [
        {
            mapping: 'id',
            name: 'id',
            type: 'int'
        },
        {
            mapping: 'client_id',
            name: 'client_id',
            type: 'int'
        },
        {
            mapping: 'client_name',
            name: 'client_name',
            type: 'string'
        },
        {
            dateFormat: 'Y-m-d',
            dateReadFormat: '',
            mapping: 'issue_date',
            name: 'issue_date',
            sortType: 'asDate',
            type: 'date'
        },
        {
            dateFormat: 'Y-m-d',
            mapping: 'due_date',
            name: 'due_date',
            sortType: 'asDate',
            type: 'date'
        },
        {
            mapping: 'payment_date',
            name: 'payment_date',
            sortType: 'asDate',
            type: 'date',
            useNull: true
        },
        {
            name: 'amount'
        },
        {
            mapping: 'invoice_status_id',
            name: 'invoice_status_id',
            sortType: 'asInt',
            type: 'int'
        }
    ],

    hasOne: {
        model: 'MyApp.model.InvoiceStatus',
        foreignKey: 'invoice_status_id',
        getterName: 'getStatus'
    }
});

InvoiceStatus Model

Ext.define('MyApp.model.InvoiceStatus', {
    extend: 'Ext.data.Model',

    fields: [
        {
            mapping: 'id',
            name: 'id',
            type: 'int'
        },
        {
            mapping: 'name',
            name: 'name',
            type: 'string'
        }
    ]
});

Invoice Grid

Ext.define('MyApp.view.ApplicationViewport', {
    extend: 'Ext.container.Viewport',

    requires: [
        'MyApp.view.ClearTriggerField'
    ],

    layout: {
        type: 'border'
    },

    initComponent: function() {
        var me = this;

        Ext.applyIf(me, {
            items: [
                {
                    xtype: 'header',
                    region: 'north',
                    height: 100,
                    items: [
                        {
                            xtype: 'image',
                            height: 100,
                            width: 250,
                            alt: 'Logo',
                            src: 'images/logo.gif',
                            title: 'Logo'
                        }
                    ]
                },
                {
                    xtype: 'container',
                    region: 'center',
                    layout: {
                        type: 'card'
                    },
                    items: [
                        {
                            xtype: 'container',
                            width: 150,
                            layout: {
                                type: 'border'
                            },
                            items: [
                                {
                                    xtype: 'gridpanel',
                                    collapseMode: 'mini',
                                    region: 'west',
                                    split: true,
                                    autoRender: false,
                                    maxWidth: 300,
                                    width: 250,
                                    bodyBorder: false,
                                    animCollapse: false,
                                    collapsed: false,
                                    collapsible: true,
                                    hideCollapseTool: true,
                                    overlapHeader: false,
                                    titleCollapse: true,
                                    allowDeselect: true,
                                    columnLines: false,
                                    forceFit: true,
                                    store: 'ClientDataStor',
                                    dockedItems: [
                                        {
                                            xtype: 'toolbar',
                                            dock: 'top',
                                            items: [
                                                {
                                                    xtype: 'cleartrigger'
                                                },
                                                {
                                                    xtype: 'tbfill'
                                                },
                                                {
                                                    xtype: 'button',
                                                    icon: '/images/settings.png'
                                                }
                                            ]
                                        }
                                    ],
                                    columns: [
                                        {
                                            xtype: 'templatecolumn',
                                            tpl: [
                                                '<img class="pull-left client-menu-image" src="/images/{type}.png"><div class="client-menu-name">{name}</div><div class="client-menu-type">{type}</div>'
                                            ],
                                            dataIndex: 'id',
                                            text: 'Client'
                                        }
                                    ],
                                    selModel: Ext.create('Ext.selection.RowModel', {

                                    }),
                                    plugins: [
                                        Ext.create('Ext.grid.plugin.BufferedRenderer', {

                                        })
                                    ]
                                },
                                {
                                    xtype: 'gridpanel',
                                    region: 'center',
                                    title: 'Invoices',
                                    titleCollapse: false,
                                    forceFit: true,
                                    store: 'Invoice',
                                    columns: [
                                        {
                                            xtype: 'numbercolumn',
                                            maxWidth: 120,
                                            minWidth: 50,
                                            dataIndex: 'id',
                                            groupable: false,
                                            lockable: true,
                                            text: 'ID',
                                            tooltip: 'Invoice ID',
                                            format: '0'
                                        },
                                        {
                                            xtype: 'numbercolumn',
                                            hidden: true,
                                            maxWidth: 120,
                                            minWidth: 50,
                                            dataIndex: 'client_id',
                                            groupable: true,
                                            text: 'Client ID',
                                            format: '0'
                                        },
                                        {
                                            xtype: 'gridcolumn',
                                            renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
                                                return record.getStatus().get('name');
                                            },
                                            maxWidth: 200,
                                            minWidth: 100,
                                            dataIndex: 'invoice_status_id',
                                            text: 'Status'
                                        },
                                        {
                                            xtype: 'datecolumn',
                                            maxWidth: 200,
                                            minWidth: 100,
                                            dataIndex: 'issue_date',
                                            text: 'Issue Date',
                                            format: 'd M Y'
                                        },
                                        {
                                            xtype: 'datecolumn',
                                            maxWidth: 200,
                                            minWidth: 100,
                                            dataIndex: 'due_date',
                                            text: 'Due Date',
                                            format: 'd M Y'
                                        },
                                        {
                                            xtype: 'datecolumn',
                                            maxWidth: 200,
                                            minWidth: 100,
                                            dataIndex: 'payment_date',
                                            text: 'Payment Date',
                                            format: 'd M Y'
                                        },
                                        {
                                            xtype: 'templatecolumn',
                                            summaryType: 'sum',
                                            maxWidth: 150,
                                            minWidth: 50,
                                            tpl: [
                                                '${amount}'
                                            ],
                                            defaultWidth: 80,
                                            dataIndex: 'amount',
                                            groupable: true,
                                            text: 'Amount'
                                        }
                                    ],
                                    features: [
                                        {
                                            ftype: 'grouping'
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        });

        me.callParent(arguments);
    }

});

回答1:


I managed to get the association lookup working by using a callback function but found it much easier to simply do the lookup from the store myself.

Step One

I moved the Proxy from the InvoiceStatus store and onto the InvoiceStatus model and made the InvoiceStatus store autoload.

Step Two

I changed the render method of the Status column to lookup the display name from the InvoiceStatus store like so.

renderer: function(value, metaData, record, rowIndex, colIndex, store, view) {
    var store = Ext.data.StoreManager.lookup('InvoiceStatus');
    return store.getById(value).get('name');
},

This proved to be a much simpeler solution.




回答2:


It looks like you need to set the belongsTo association on the InvoiceStatus child model. You would think that defining the association in one direction would automatically create the association in the other direction, but apparently that's not the case and you must define the association on both parent and children. See here for a more detailed explanation: Why isn't my ExtJS Store Association Working




回答3:


Your hasOne should be like this:

hasOne: {
    name:           'status',
    instanceName:   'status',
    associationKey: 'status',
    model:          'MyApp.model.InvoiceStatus',
    foreignKey:     'invoice_status_id',
    getterName:     'getStatus',
    setterName:     'setStatus'
}

The following patch for ExtJS 4.2.2 will let you set dataIndex: 'status.name' without any additional renderers. Grid will show everything OK but sorting will not work.

This solution does not work with async (lazy) status load.

Ext.view.Table.prototype.renderCell = function(column, record, recordIndex, rowIndex, columnIndex, out) {
    var me = this,
        selModel = me.selModel,
        cellValues = me.cellValues,
        classes = cellValues.classes,
        // fieldValue = record.data[column.dataIndex]; // patched
        fieldValue = null,
        cellTpl = me.cellTpl,
        fullIndex, value, clsInsertPoint;

    // Patch start
    if (column.dataIndex && column.dataIndex.indexOf('.') > 0) {
        var associationParts = column.dataIndex.split('.'),
            v = record;

        for (var i = 0; i < associationParts.length-1; i++) {
            v = v['get' + associationParts[i].charAt(0).toUpperCase() + associationParts[i].slice(1)]();
        }
        fieldValue = v.get(associationParts[associationParts.length-1]);
    }
    else {
        fieldValue = record.data[column.dataIndex];
    }
    // Patch end

    cellValues.record = record;
    cellValues.column = column;
    cellValues.recordIndex = recordIndex;
    cellValues.rowIndex = rowIndex;
    cellValues.columnIndex = columnIndex;
    cellValues.cellIndex = columnIndex;
    cellValues.align = column.align;
    cellValues.tdCls = column.tdCls;
    cellValues.innerCls = column.innerCls;
    cellValues.style = cellValues.tdAttr = "";
    cellValues.unselectableAttr = me.enableTextSelection ? '' : 'unselectable="on"';

    if (column.renderer && column.renderer.call) {
        fullIndex = me.ownerCt.columnManager.getHeaderIndex(column);
        value = column.renderer.call(column.scope || me.ownerCt, fieldValue, cellValues, record, recordIndex, fullIndex, me.dataSource, me);
        if (cellValues.css) {
            // This warning attribute is used by the compat layer
            // TODO: remove when compat layer becomes deprecated
            record.cssWarning = true;
            cellValues.tdCls += ' ' + cellValues.css;
            delete cellValues.css;
        }
    } else {
        value = fieldValue;
    }
    cellValues.value = (value == null || value === '') ? '&#160;' : value;

    // Calculate classes to add to cell
    classes[1] = column.getCellId();

    // On IE8, array[len] = 'foo' is twice as fast as array.push('foo')
    // So keep an insertion point and use assignment to help IE!
    clsInsertPoint = 2;

    if (column.tdCls) {
        classes[clsInsertPoint++] = column.tdCls;
    }
    if (me.markDirty && record.isModified(column.dataIndex)) {
        classes[clsInsertPoint++] = me.dirtyCls;
    }
    if (column.isFirstVisible) {
        classes[clsInsertPoint++] = me.firstCls;
    }
    if (column.isLastVisible) {
        classes[clsInsertPoint++] = me.lastCls;
    }
    if (!me.enableTextSelection) {
        classes[clsInsertPoint++] = me.unselectableCls;
    }
    if (cellValues.tdCls) {
        classes[clsInsertPoint++] = cellValues.tdCls;
    }
    if (selModel && selModel.isCellModel && selModel.isCellSelected(me, recordIndex, columnIndex)) {
        classes[clsInsertPoint++] = (me.selectedCellCls);
    }

    // Chop back array to only what we've set
    classes.length = clsInsertPoint;

    cellValues.tdCls = classes.join(' ');

    cellTpl.applyOut(cellValues, out);

    // Dereference objects since cellValues is a persistent var in the XTemplate's scope chain
        cellValues.column = null;
};


来源:https://stackoverflow.com/questions/16005891/ext-js-4-use-an-model-association-to-render-a-grid-display-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!