Threaded View

  1. #1
    Sencha - Community Support Team
    Join Date
    Jan 2012
    Posts
    1,376
    Vote Rating
    115
    vietits is a splendid one to behold vietits is a splendid one to behold vietits is a splendid one to behold vietits is a splendid one to behold vietits is a splendid one to behold vietits is a splendid one to behold

      1  

    Default Its.grid.column.Component

    Its.grid.column.Component


    This component allows you to render a component or a series of components in one or more grid cells. Document and guide how to use are included in the component source code.

    Latest version: 2.3 (released on 2012-05-05)

    Ext compatible versions: Ext 4.0.7, Ext 4.1.0-rc3, Ext 4.1.0-gpl.

    Below is the screenshot of grid using this component to render some kinds of components, such as: chart, combobox, spinner, date picker, checkbox, button.

    grid-component.jpg

    Change log
    2012-01-14: Release version 1.0
    2012-01-24: Release version 2.0 with the following updates:
    • Remove relayEvents, eventPrefix and prefixEvent from component config which can be replaced by bubbleEvents.
    • Add ownerCt to reflect component's owner container.
    • Item config now can be a function.
    • Fix the destroy()method.
    2012-03-17: Release version 2.1with the following updates:
    • Append record and store to event arguments
    • Update internal code
    2012-04-23: Release version 2.2 with the following updates:
    • Update internal code
    2012-05-05: Release version 2.3 with the following updates:
    • Update internal code
    Source code
    Code:
    /**
     * @class Its.grid.column.Component
     * @extends Ext.grid.column.Column
     * @xtype itscomponentcolumn
     * @version 2.3
     * @author Nguyen Truong Sinh (vietits@yahoo.com)
     *
     * A column definition class which renders a component, or a series of components in a grid cell.
     * 
     *     @example
     *     var store = Ext.create('Ext.data.Store', {
     *         fields:['taskname', 'status', 'assignTo', 'dep'],
     *         data:[
     *             {taskname:"Task 1", status:1, assignTo:"Scott", dep:"Manangement"},
     *             {taskname:"Task 2", status:2, assignTo:"John", dep:"Sales"},
     *             {taskname:"Task 3", status:2, assignTo:"Smith", dep:"Accounting"},
     *             {taskname:"Task 4", status:3, assignTo:"Smith", dep:"Accounting"}
     *         ]
     *     });
     *
     *     Ext.create('Ext.grid.Panel', {
     *         title: 'Component Column Demo',
     *         name : 'task',
     *         store: store,
     *         columns: [{
     *          .......
     *          },{ // a column with a combobox
     *              xtype: 'itscomponentcolumn',
     *              text : 'Status',
     *              width: 160,
     *              name : 'status',
     *              dataIndex: 'status',
     *              items: {
     *                  prepare: function(config, value) {
     *                      return { 
     *                          xtype: 'combobox',
     *                          store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']], 
     *                          value: value
     *                      }; 
     *                  }
     *              }
     *          },{ // a column with two buttons to modify/delete task
     *              xtype: 'itscomponentcolumn',
     *              align: 'center',
     *              width: 50,
     *              name : 'action',
     *              defaults: { // default configs applied for all items
     *                  xtype: 'button',
     *                  width: 'auto'
     *              },
     *              items: [{
     *                  iconCls: 'icon-modify',
     *                  action : 'modify',
     *                  tooltip: 'Modify this task'
     *              },{
     *                  iconCls: 'icon-delete',
     *                  action : 'delete',
     *                  tooltip: 'Delete this task'
     *              }]
     *         }],
     *         width: 400,
     *         renderTo: Ext.getBody()
     *     });
     *
     * # Default settings
     *
     * - hideable: false
     * - groupable: false
     * - defaultType: 'component'
     *
     * # Child component events
     *
     * The following arguments will be added to the end of argument list of each event:
     *
     * - record The record providing the data.
     * - rowIndex The row index.
     * - colIndex The column index.
     * - store The store which provides model data
     * - view The grid view object.
     * - comp The component itself.
     *
     * @update 2012-01-14 22:37:21
     *  Release version 1.0
     *
     * @update 2012-01-24 08:37:09
     *  Release version 2.0 with the following updates:
     *  - Remove relayEvents, eventPrefix and prefixEvent from component config which can be replaced by bubbleEvents and bubblePrefix.
     *  - Add ownerCt to reflect component's owner container.
     *  - Add the ability that is an item config can be a function.
     *  - Fix the destroy() method.
     *
     * @update 2012-03-17 21:23:34
     *  Release version 2.1 with the following updates:
     *  - Append record and store to event arguments 
     *  - Update internal code
     * @update 2012-04-23 19:48:46
     *  Release version 2.2 with the following updates:
     *  - Update internal code
     * @update 2012-05-05 09:58:07
     *  Release version 2.3 with the following updates:
     *  - Update internal code
     */
    
    
    Ext.define('Its.grid.column.Component', {
        extend: 'Ext.grid.column.Column',
        alias : 'widget.itscomponentcolumn',
    
    
        /**
         * @cfg {String/Function/Object/String[]/Function[]/Object[]} items
         * Child component configs. Items can be:
         * - an xtype (string) or array of xtype (string[])
         * - a function which returns item config object or an array of functions. 
         *   Function will be called with following arguments:
         *   + value The value of the column's configured field (if any).
         *   + record The record providing the data.
         *   + rowIndex The row index.
         *   + colIndex The column index.
         *   + store The store which is providing the data Model.
         *   + view The current view.
         * - an object which represents item conig or an array of config objects
         * - mix of above types.
         *
         * Besides the normal component configs, each item may contain:
         *
         * @cfg {Function} items.prepare A function which returns the component config.
         * @cfg {Object} items.prepare.config The current config.
         * @cfg {Object} items.prepare.value The value of the column's configured field (if any).
         * @cfg {Ext.data.Model} items.prepare.record The record providing the data.
         * @cfg {Number} items.prepare.rowIndex The row index.
         * @cfg {Number} items.prepare.colIndex The column index.
         * @cfg {Ext.data.Store} items.prepare.store The store which is providing the data Model.
         * @cfg {Ext.grid.View} items.prepare.view The current view.
         *
         * @cfg {Object} items.scope The scope (`this` reference) in which the `prepare` function
         * is executed. 
         */
        
        constructor: function(config) {
            var me  = this;
            var cfg = Ext.apply({
                hideable: false,
                groupable: false,
                defaultType: 'component'
            }, config);
            var lst = cfg.items;
            var def = cfg.defaults;
    
    
            delete cfg.items;
            delete cfg.columns;
            delete cfg.defaults;
            
            me.callParent([cfg]);
    
    
            me.defaults = def;
            me.queue = {};
            me.comps = Ext.create('Ext.util.MixedCollection', false, me.getComponentId);
            me.itemsConfig = [];
            lst = Ext.isArray(lst) ? lst : [lst];
            Ext.Array.each(lst, function(itm) {
                if(Ext.isString(itm)) {
                    itm = {xtype: itm};
                }
                if(Ext.isObject(itm) || Ext.isFunction(itm)) {
                    me.itemsConfig.push(itm);
                }
            });
    
    
            me.renderer = function(value, meta, record, rowIdx, colIdx, store, view) {
                var ret = '';
                var src = me.renderer.caller;
                if (src.$owner && src.$owner.xtype == 'headercontainer') {
                    var iid = me.getIdPrefix(record);
                    me.queue[iid] = {
                        view  : view,
                        store : store,
                        value : value,
                        record: record,
                        rowIdx: rowIdx,
                        colIdx: colIdx
                    };
                    ret = (Ext.isFunction(cfg.renderer) ? cfg.renderer.apply(cfg.scope  || me, arguments) || '' : '') 
                        + '<div id="' + iid + '">&#160;</div>';
                }
                return ret;
            };
        },
        onRender: function() {
            var me  = this;
            var pnl = me.up('tablepanel');
            var view= pnl.getView();
    
    
            me.mon(view, 'refresh'   , me.injectItems, me);
            me.mon(view, 'itemadd'   , me.injectItems, me); 
            me.mon(view, 'itemupdate', me.injectItems, me);
            me.callParent(arguments);
        },
        getIdPrefix : function(record) {
            return Ext.String.format('{0}-{1}', this.getId(), record.internalId);
        },
        injectItems: function() {
            var me  = this;
            var queue = me.queue;
            var items = me.itemsConfig;
            var cfLen = items.length;
    
    
            me.queue = {};
            for(var iid in queue) {
                var itm = queue[iid];
                var elm = Ext.get(iid);
                if(elm) {
                    for(var idx = 0; idx < cfLen; idx++) {
                        var cfg = Ext.clone(items[idx]) || {};
    
    
                        if(Ext.isFunction(cfg)) {
                            cfg = cfg(itm.value, itm.record, itm.rowIdx, itm.colIdx, itm.store, itm.view);
                        }
                        if(Ext.isFunction(cfg.prepare)) {
                            cfg = cfg.prepare.call(cfg.scope || cfg, cfg, itm.value, itm.record, itm.rowIdx, itm.colIdx, itm.store, itm.view);
                        }
                        delete cfg.prepare;
                        cfg = me.applyDefaults(cfg);
    
    
                        cfg.itemId = iid + '-' + idx;
    
    
                        me.removeItem(cfg.itemId);
                        
                        var cmp = me.lookupComponent(cfg);
                        if(cmp && cmp.isComponent) {
                            cmp.fireEvent = Ext.bind(cmp.fireEvent, cmp, [itm.record, itm.rowIdx, itm.colIdx, itm.store, itm.view, cmp], true);
                            cmp.render(elm.parent(), elm);
                            if (Ext.isIE6) {
                                elm.parent().repaint();
                            }
                            cmp.ownerCt = me;
                            me.comps.add(cmp);
                        }
                    }
                    elm.remove();
                }
            }
        },
        onItemRemove: function(record) {
            var me = this;
            var iid = me.getIdPrefix(record);
            var idx = 0;
    
    
            while(me.removeItem(iid + '-' + idx)) {
                idx++;
            }
        },
        removeItem: function(cmp) {
            var me  = this;
            var ret = false;
    
    
            if(Ext.isString(cmp)) {
                cmp = me.comps.getByKey(cmp);
            }
            if(cmp) {
                cmp.ownerCt = null;
                me.comps.remove(cmp);
                cmp.destroy();
                ret = true;
            }
            return ret;
        },
        $callParent: function(args) {
            var me  = this;
            var ret = null;
            var method = me.$callParent.caller,
                parentClass, methodName;
    
    
            if (!method.$owner) {
                method = method.caller;
            }
            parentClass = method.$owner.superclass;
            methodName  = method.$name;
    
    
            if(me.items === me.comps) {
                ret = parentClass[methodName].apply(me, args || []);
            } else {
                var items = me.items;
                me.items = me.comps;
                ret = parentClass[methodName].apply(me, args || []);
                me.items = items;
            }
            return ret;
        },
        beforeDestroy: function() {
            var me  = this;
    
    
            me.$callParent(arguments);
            Ext.destroyMembers(me, 'comps', 'queue', 'renderer');
        },
        doRemove: function(cmp) {
            this.$callParent(arguments)
        },
        removeAll: function() {
            return this.$callParent(arguments);
        },
        getComponent: function() {
            return this.$callParent(arguments);
        },
        getRefItems: function() {
            return this.$callParent(arguments);
        },
        cascade: false
    });
    Example
    Code:
     Ext.require([
        'Ext.picker.*',
        'Ext.form.*',
        'Ext.grid.*',
        'Ext.data.*',
        'Ext.panel.*',
        'Ext.chart.*',
        'Ext.chart.axis.Gauge',
        'Ext.chart.series.*',
        'Its.grid.column.Component'
    ]);
    
    Ext.onReady(function() {
        var store = Ext.create('Ext.data.Store', {
            fields:['taskname', 'status', 'done', 'assignTo', 'dep', 'date', {name:'qty', type: 'int'}],
            data:[
                {taskname:"Task 1", status:1, done: 10, assignTo:"Scott", dep:"Manangement", date: '2012-01-01', qty:20},
                {taskname:"Task 2", status:2, done: 30, assignTo:"John", dep:"Sales", date: '2012-01-12', qty:35},
                {taskname:"Task 3", status:2, done: 50, assignTo:"Smith", dep:"Accounting", date: '2012-01-21', qty:12},
                {taskname:"Task 4", status:3, done: 70, assignTo:"Smith", dep:"Accounting", date: '2012-01-05', qty:51}
            ]
        });
     
        Ext.create('Ext.grid.Panel', {
            title: 'Component Column Demo',
            name : 'task',
            store: store,
            width: 900,
            height: 950,
            renderTo: Ext.getBody(),
            columns: [{
                text: 'Task name',
                flex: 1,
                dataIndex: 'taskname'
            },{ // chart column
                xtype: 'itscomponentcolumn',
                text : 'Chart',
                width: 200,
                dataIndex: 'done',
                items: function(value) {
                    return {
                        xtype: 'chart',
                        width: 200,
                        height: 150,
                        style: 'background:#fff',
                        animate: {
                            easing: 'elasticIn',
                            duration: 1000
                        },
                        store: Ext.create('Ext.data.Store', {
                            fields: ['gauge'],
                            data  : [{gauge: value}]
                        }),
                        insetPadding: 25,
                        flex: 1,
                        axes: [{
                            type: 'gauge',
                            position: 'gauge',
                            minimum: 0,
                            maximum: 100,
                            steps: 10,
                            margin: -10
                        }],
                        series: [{
                            type: 'gauge',
                            value: value,
                            field: 'gauge',
                            donut: false,
                            colorSet: ['#F49D10', '#ddd']
                        }]
                    }
                }
            },{ // column with a combobox
                    xtype: 'itscomponentcolumn',
                    text : 'Combobox',
                    name : 'status',
                    width: 160,
                    dataIndex: 'status',
                    items: function(value) {
                        return { 
                            xtype: 'combobox',
                            store: [[1,'In Queue'], [2,'Handling'], [3,'Complete']], 
                            value: value,
                            width: 130
                        }; 
                    }
                },{ // column with a spinner
                    xtype: 'itscomponentcolumn',
                    text : 'Spinner',
                    width: 50,
                    dataIndex: 'qty',
                    items: function(value) {
                        return {
                            xtype: 'spinnerfield',
                            value: value,
                            width: 25
                        };
                    }
                },{ // column with date picker
                    xtype: 'itscomponentcolumn',
                    text : 'Date picker',
                    dataIndex: 'date',
                    width: 200,
                    items: function(value) {
                        return {
                            xtype: 'datepicker',
                            width: 190,
                            value: new Date(value)
                        };
                    }
                },{ // column with checkboxes
                    xtype: 'itscomponentcolumn',
                    text : 'Checkbox',
                    defaultType: 'checkboxfield',
                    items: [{
                        boxLabel  : 'Anchovies',
                        name      : 'topping',
                        inputValue: '1',
                    }, {
                        boxLabel  : 'Artichoke Hearts',
                        name      : 'topping',
                        inputValue: '2',
                        checked   : true,
                    }, {
                        boxLabel  : 'Bacon',
                        name      : 'topping',
                        inputValue: '3',
                    }]
                },{ // column with two buttons
                    xtype: 'itscomponentcolumn',
                    text : 'Buttons',
                    align: 'center',
                    width: 60,
                    name : 'action',
                    sortable: false,
                    defaults: { // default configs applied for all items
                        xtype: 'button',
                        width: 'auto'
                    },
                    items: [{
                        iconCls: 'icon-modify',
                        action : 'modify',
                        tooltip: 'Modify this task'
                    },{
                        iconCls: 'icon-delete',
                        action : 'delete',
                        tooltip: 'Delete this task'
                    }]
              }]
          });
    });
    Last edited by vietits; 4 May 2012 at 7:09 PM. Reason: Release version 2.3