1. #1
    Ext User
    Join Date
    Jul 2007
    Posts
    3,128
    Vote Rating
    0
    devnull has a little shameless behaviour in the past

      0  

    Default Improved PropertyGrid

    Improved PropertyGrid


    I recently worked with the PropertyGrid on a project and found it rather... lacking. It is in it's shipped state very hard to use, not intuitive at all, and has limited documentation. With all of this, I assumed the PropertyGrid could be used almost as a drop-in replacement for a normal GridPanel. This is of course incorrect, but many other people seem to make the same mistake, so it seemed worthwhile to modify it to act more like a normal grid.
    It actually works more like a formPanel though really, but just because it can only work with one record at a time. I use several of them in a portal layout to "section" a record into related panels, with a 'beforepropertychange' listener that commits changes back to the original record.
    I gave it an xtype of 'propertygrid2' for lack of any better ideas, but that is easy enough to change for anyone that cares.

    New config properties:
    fields
    An array of property definitions, one per each 'row' to appear in the Grid. This is meant to emulate the 'columns' config of a normal Grid. If this is upplied, only fields defined within this property will ever be displayed, regardless of what is supplied in the source.
    Valid member options:
    id: id of the property. not really used right now, but should be supplied.
    dataIndex: name of the field in the source to use as this property's value component.
    header: text to display as this property's name.
    editor: custom Ext.grid.GridEditor to use for this property.
    renderer: renderer function for this property's value. supplies the same arguments as a normal grid renderer. keep in mind that the record supplied is a PropertyRecord, which contains only data related to this property.
    editable: editable status of this property. defaults to true.
    ex:
    Code:
    [{
      id: 'fname',
      dataIndex: 'fname',
      header: 'First Name',
      editable: false
    }, {
      id: 'lname',
      dataIndex: 'lname',
      header: 'Last Name',
      editable: false
    }, {
      id: 'id',
      dataIndex: 'id',
      header: 'Employee ID',
      editor: new Ext.grid.GridEditor(new Ext.form.NumberField({selectOnFocus:true, style:'text-align:left;'})),
      renderer: function(val, metadata, record, rowIndex, colIndex, store) {
        metaData.attr += ' style="color:red"';
      }
    }
    nameWidth
    Width of the 'name' column. default 50.
    valueWidth
    Width of the 'value' column. default 50.
    autoExpandColumn
    Column to auto expand to use available space. default 'value'.
    editable
    Boolean to enable editing of all properties in this grid. default true.

    Also added a couple new methods:
    load()
    Loads a simple object into the grid. Identical to setSource().
    loadRecord()
    Loads an Ext.Record into the grid.

    Source:
    PHP Code:
    /*
     * Ext JS Library 2.1
     * Copyright(c) 2006-2008, Ext JS, LLC.
     * licensing@extjs.com
     * 
     * http://extjs.com/license
     */
    Ext.namespace('Ext.ux.grid');
    /**
     * @class Ext.grid.PropertyRecord
     * A specific {@link Ext.data.Record} type that represents a name/value pair and is made to work with the
     * {@link Ext.grid.PropertyGrid}.  Typically, PropertyRecords do not need to be created directly as they can be
     * created implicitly by simply using the appropriate data configs either via the {@link Ext.grid.PropertyGrid#source}
     * config property or by calling {@link Ext.grid.PropertyGrid#setSource}.  However, if the need arises, these records
     * can also be created explicitly as shwon below.  Example usage:
     * <pre><code>
    var rec = new Ext.grid.PropertyRecord({
        name: 'Birthday',
        value: new Date(Date.parse('05/26/1972'))
    });
    // Add record to an already populated grid
    grid.store.addSorted(rec);
    </code></pre>
     * @constructor
     * @param {Object} config A data object in the format: {name: [name], value: [value]}.  The specified value's type
     * will be read automatically by the grid to determine the type of editor to use when displaying it.
     */
    Ext.ux.grid.PropertyRecord Ext.data.Record.create([
        {
    name:'name',type:'string'}, 'value''header''field'
    ]);

    /**
     * @class Ext.grid.PropertyStore
     * @extends Ext.util.Observable
     * A custom wrapper for the {@link Ext.grid.PropertyGrid}'s {@link Ext.data.Store}. This class handles the mapping
     * between the custom data source objects supported by the grid and the {@link Ext.grid.PropertyRecord} format
     * required for compatibility with the underlying store. Generally this class should not need to be used directly --
     * the grid's data should be accessed from the underlying store via the {@link #store} property.
     * @constructor
     * @param {Ext.grid.Grid} grid The grid this store will be bound to
     * @param {Object} source The source data config object
     */
    Ext.ux.grid.PropertyStore = function(gridsource){
        
    this.grid grid;
        
    this.store = new Ext.data.Store({
            
    recordType Ext.grid.PropertyRecord
        
    });
            
    this.store.loadRecords = function(ooptionssuccess){
            if(!
    || success === false){
                if(
    success !== false){
                    
    this.fireEvent("load"this, [], options);
                }
                if(
    options.callback){
                    
    options.callback.call(options.scope || this, [], optionsfalse);
                }
                return;
            }
            var 
    o.recordso.totalRecords || r.length;
            if(!
    options || options.add !== true){
                if(
    this.pruneModifiedRecords){
                    
    this.modified = [];
                }
                for(var 
    0len r.lengthleni++){
                    
    r[i].join(this);
                }
                if(
    this.snapshot){
                    
    this.data this.snapshot;
                    
    delete this.snapshot;
                }
                
    this.data.clear();
                
    this.data.addAll(r);
                
    this.totalLength t;
                
    //this.applySort();
                
    this.fireEvent("datachanged"this);
            }else{
                
    this.totalLength Math.max(tthis.data.length+r.length);
                
    this.add(r);
            }
            
    this.fireEvent("load"thisroptions);
            if(
    options.callback){
                
    options.callback.call(options.scope || thisroptionstrue);
            }
        }
        
    this.store.on('update'this.onUpdate,  this);
        if(
    source){
            
    this.setSource(source);
        }
        
    Ext.ux.grid.PropertyStore.superclass.constructor.call(this);
    };
    Ext.extend(Ext.ux.grid.PropertyStoreExt.util.Observable, {
        
    // protected - should only be called by the grid.  Use grid.setSource instead.
        
    setSource : function(o,fields){
            
    this.source o;
            
    this.store.removeAll();
            var 
    data = [];
                    if (
    fields) {
                        for (var 
    k in fields) {
                            
    k=fields[k];
                            if (
    typeof(k) == 'object'){
                            
    //if (k.id && this.isEditableValue(o[k.dataIndex])) {
                                
    data.push(new Ext.grid.PropertyRecord({
                                    
    namek.dataIndex,
                                    
    valueo[k.dataIndex],
                                    
    headerk.header,
                                    
    fieldk
                                
    }, k.id));
                            }
                        }
                    } else {
                        for (var 
    k in o) {
                            if (
    this.isEditableValue(o[k])) {
                                
    data.push(new Ext.grid.PropertyRecord({
                                    
    namek,
                                    
    valueo[k],
                                    
    headerk
                                
    }, k));
                            }
                        }
                    }
            
    this.store.loadRecords({recordsdata}, {}, true);
        },

        
    // private
        
    onUpdate : function(dsrecordtype){
            if(
    type == Ext.data.Record.EDIT){
                var 
    record.data['value'];
                var 
    oldValue record.modified['value'];
                if(
    this.grid.fireEvent('beforepropertychange'this.sourcerecord.idvoldValue) !== false){
                    
    this.source[record.id] = v;
                    
    record.commit();
                    
    this.grid.fireEvent('propertychange'this.sourcerecord.idvoldValue);
                }else{
                    
    record.reject();
                }
            }
        },

        
    // private
        
    getProperty : function(row){
           return 
    this.store.getAt(row);
        },

        
    // private
        
    isEditableValue: function(val){
            if(
    Ext.isDate(val)){
                return 
    true;
            }else if(
    typeof val == 'object' || typeof val == 'function'){
                return 
    false;
            }
            return 
    true;
        },

        
    // private
        
    setValue : function(propvalue){
            
    this.source[prop] = value;
            
    this.store.getById(prop).set('value'value);
        },

        
    // protected - should only be called by the grid.  Use grid.getSource instead.
        
    getSource : function(){
            return 
    this.source;
        }
    });

    /**
     * @class Ext.grid.PropertyColumnModel
     * @extends Ext.grid.ColumnModel
     * A custom column model for the {@link Ext.grid.PropertyGrid}.  Generally it should not need to be used directly.
     * @constructor
     * @param {Ext.grid.Grid} grid The grid this store will be bound to
     * @param {Object} source The source data config object
     */
    Ext.ux.grid.PropertyColumnModel = function(gridstore){
        
    this.grid grid;
        var 
    Ext.grid;
        
    Ext.ux.grid.PropertyColumnModel.superclass.constructor.call(this, [
            {
    headerthis.nameTextwidth:grid.nameWidthsortabletruedataIndex:'header'id'name'menuDisabled:true},
            {
    headerthis.valueTextwidth:grid.valueWidthresizable:falsedataIndex'value'id'value'menuDisabled:true}
        ]);
        
    this.store store;
        
    this.bselect Ext.DomHelper.append(document.body, {
            
    tag'select'cls'x-grid-editor x-hide-display'children: [
                {
    tag'option'value'true'html'true'},
                {
    tag'option'value'false'html'false'}
            ]
        });
        var 
    Ext.form;

        var 
    bfield = new f.Field({
            
    el:this.bselect,
            
    bselect this.bselect,
            
    autoShowtrue,
            
    getValue : function(){
                return 
    this.bselect.value == 'true';
            }
        });
        
    this.editors = {
            
    'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
            
    'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
            
    'number' : new g.GridEditor(new f.NumberField({selectOnFocus:truestyle:'text-align:left;'})),
            
    'boolean' : new g.GridEditor(bfield)
        };
        
    this.renderCellDelegate this.renderCell.createDelegate(this);
        
    this.renderPropDelegate this.renderProp.createDelegate(this);
    };

    Ext.extend(Ext.ux.grid.PropertyColumnModelExt.grid.ColumnModel, {
        
    // private - strings used for locale support
        
    nameText 'Name',
        
    valueText 'Value',
        
    dateFormat 'm/j/Y',

        
    // private
        
    renderDate : function(dateVal){
            return 
    dateVal.dateFormat(this.dateFormat);
        },

        
    // private
        
    renderBool : function(bVal){
            return 
    bVal 'true' 'false';
        },

        
    // private
        
    isCellEditable : function(colIndexrowIndex){
                var 
    this.store.getProperty(rowIndex);
                if (
    p.data.field && p.data.field.editable == false) {
                        return 
    false;
                    }
            return 
    colIndex == 1;
        },

        
    // private
        
    getRenderer : function(col){
            return 
    col == ?
                
    this.renderCellDelegate this.renderPropDelegate;
        },

        
    // private
        
    renderProp : function(v){
            return 
    this.getPropertyName(v);
        },

        
    // private
        
    renderCell : function(valmetadatarecordrowIndexcolIndexstore){
                
                if (
    record.data.field && typeof(record.data.field.renderer) == 'function'){
                    return 
    record.data.field.renderer.call(thisvalmetadatarecordrowIndexcolIndexstore);
                }
            var 
    rv val;
            if(
    Ext.isDate(val)){
                
    rv this.renderDate(val);
            }else if(
    typeof val == 'boolean'){
                
    rv this.renderBool(val);
            }
            return 
    Ext.util.Format.htmlEncode(rv);
        },

        
    // private
        
    getPropertyName : function(name){
            var 
    pn this.grid.propertyNames;
            return 
    pn && pn[name] ? pn[name] : name;
        },

        
    // private
        
    getCellEditor : function(colIndexrowIndex){
            var 
    this.store.getProperty(rowIndex);
            var 
    p.data['name'], val p.data['value'];
                    if(
    p.data.field && typeof(p.data.field.editor) == 'object'){
                return 
    p.data.field.editor;
            }
            if(
    typeof(this.grid.customEditors) == 'function'){
                return 
    this.grid.customEditors(n);
            }
            if(
    Ext.isDate(val)){
                return 
    this.editors['date'];
            }else if(
    typeof val == 'number'){
                return 
    this.editors['number'];
            }else if(
    typeof val == 'boolean'){
                return 
    this.editors['boolean'];
            }else{
                return 
    this.editors['string'];
            }
        }
    });

    /**
     * @class Ext.grid.PropertyGrid
     * @extends Ext.grid.EditorGridPanel
     * A specialized grid implementation intended to mimic the traditional property grid as typically seen in
     * development IDEs.  Each row in the grid represents a property of some object, and the data is stored
     * as a set of name/value pairs in {@link Ext.grid.PropertyRecord}s.  Example usage:
     * <pre><code>
    var grid = new Ext.grid.PropertyGrid({
        title: 'Properties Grid',
        autoHeight: true,
        width: 300,
        renderTo: 'grid-ct',
        source: {
            "(name)": "My Object",
            "Created": new Date(Date.parse('10/15/2006')),
            "Available": false,
            "Version": .01,
            "Description": "A test object"
        }
    });
    </pre></code>
     * @constructor
     * @param {Object} config The grid config object
     */
    Ext.ux.grid.PropertyGrid Ext.extend(Ext.grid.EditorGridPanel, {
        
    /**
        * @cfg {Object} source A data object to use as the data source of the grid (see {@link #setSource} for details).
        */
        /**
        * @cfg {Object} customEditors An object containing name/value pairs of custom editor type definitions that allow
        * the grid to support additional types of editable fields.  By default, the grid supports strongly-typed editing
        * of strings, dates, numbers and booleans using built-in form editors, but any custom type can be supported and
        * associated with a custom input control by specifying a custom editor.  The name of the editor
        * type should correspond with the name of the property that will use the editor.  Example usage:
        * <pre><code>
    var grid = new Ext.grid.PropertyGrid({
        ...
        customEditors: {
            'Start Time': new Ext.grid.GridEditor(new Ext.form.TimeField({selectOnFocus:true}))
        },
        source: {
            'Start Time': '10:00 AM'
        }
    });
    </code></pre>
        */

        // private config overrides
        
    enableColumnMove:false,
        
    stripeRows:false,
        
    trackMouseOverfalse,
        
    clicksToEdit:1,
        
    enableHdMenu false,
            
    editabletrue,
            
    nameWidth50,
            
    valueWidth50,
            
    source: {},
            
    autoExpandColumn'value',

        
    // private
        
    initComponent : function(){
            
    this.customEditors this.customEditors || {};
            
    this.lastEditRow null;
            var 
    store = new Ext.ux.grid.PropertyStore(this);
            
    this.propStore store;
            var 
    cm = new Ext.ux.grid.PropertyColumnModel(thisstore);
            
    store.store.sort('name''ASC');
            
    this.addEvents(
                
    /**
                 * @event beforepropertychange
                 * Fires before a property value changes.  Handlers can return false to cancel the property change
                 * (this will internally call {@link Ext.data.Record#reject} on the property's record).
                 * @param {Object} source The source data object for the grid (corresponds to the same object passed in
                 * as the {@link #source} config property).
                 * @param {String} recordId The record's id in the data store
                 * @param {Mixed} value The current edited property value
                 * @param {Mixed} oldValue The original property value prior to editing
                 */
                
    'beforepropertychange',
                
    /**
                 * @event propertychange
                 * Fires after a property value has changed.
                 * @param {Object} source The source data object for the grid (corresponds to the same object passed in
                 * as the {@link #source} config property).
                 * @param {String} recordId The record's id in the data store
                 * @param {Mixed} value The current edited property value
                 * @param {Mixed} oldValue The original property value prior to editing
                 */
                
    'propertychange'
            
    );
            
    this.cm cm;
            
    this.ds store.store;
            
    Ext.ux.grid.PropertyGrid.superclass.initComponent.call(this);

            
    this.selModel.on('beforecellselect', function(smrowIndexcolIndex){
                if(
    colIndex === 0){
                    
    this.startEditing.defer(200this, [rowIndex1]);
                    return 
    false;
                }
            }, 
    this);
                    if (!
    this.editable){
                        
    this.on('beforeedit', function(){return false})
                    }
        },

        
    // private
        
    onRender : function(){
            
    Ext.ux.grid.PropertyGrid.superclass.onRender.apply(thisarguments);

            
    this.getGridEl().addClass('x-props-grid');
        },

        
    // private
        
    afterRender: function(){
            
    Ext.ux.grid.PropertyGrid.superclass.afterRender.apply(thisarguments);
            if(
    this.source){
                
    this.setSource(this.source);
            }
        },

        
    /**
         * Sets the source data object containing the property data.  The data object can contain one or more name/value
         * pairs representing all of the properties of an object to display in the grid, and this data will automatically
         * be loaded into the grid's {@link #store}.  The values should be supplied in the proper data type if needed,
         * otherwise string type will be assumed.  If the grid already contains data, this method will replace any
         * existing data.  See also the {@link #source} config value.  Example usage:
         * <pre><code>
    grid.setSource({
        "(name)": "My Object",
        "Created": new Date(Date.parse('10/15/2006')),  // date type
        "Available": false,  // boolean type
        "Version": .01,      // decimal type
        "Description": "A test object"
    });
    </code></pre>
         * @param {Object} source The data object
         */
        
    setSource : function(source){
            
    this.propStore.setSource(source,this.fields);
        },
            
            
    /**
             * Loads a data object. Equivalent to setSource()
             */
            
    load : function(source){
                
    this.setSource(source);
            },
            
            
    /**
             * Loads an Ext.Record as the source data object
             */
            
    loadRecord : function(record) {
                
    record.data && this.setSource(record.data);
            },

        
    /**
         * Gets the source data object containing the property data.  See {@link #setSource} for details regarding the
         * format of the data object.
         * @return {Object} The data object
         */
        
    getSource : function(){
            return 
    this.propStore.getSource();
        }
    });
    Ext.reg("propertygrid2"Ext.ux.grid.PropertyGrid); 

  2. #2
    Sencha User
    Join Date
    Aug 2007
    Location
    NYC
    Posts
    85
    Vote Rating
    0
    JEBriggs is on a distinguished road

      0  

    Default Great Job on Improved Property Grid!

    Great Job on Improved Property Grid!


    This appears to be exactly what I need. I'm integrating it now into my application. This is much more intuitive!

    I have a master detail scenario. The property grid is the detail for the primary grid. Select a row in the primary grid and the content of the property grid changes. Sometimes the property grid has to show read only values. In this case, I'm individually setting the editability of the rows like this:
    Code:
    cm.setEditable(1, false);
    I found that I had to add the following to your PropertyGrid:
    Code:
        /**
         * Sets the second column's (value column) editable property.
         */
         
        setEditable: function(rowIndex, editable) {
          var p = this.store.getProperty(rowIndex);    	
          if(p.data.field) p.data.field.editable = editable;
        },
    Setting a grid to disabled results in an ugly gray panel. It would be nice if there was a method on the propertyGrid setReadOnly(boolean) which would set the whole grid to readonly and when you set it back to editable, the grid remembers the rows that are never editable. But that's just a nicety that isn't found in the original either.

    So thanks for the contribution!

  3. #3
    Ext User
    Join Date
    Jul 2007
    Posts
    3,128
    Vote Rating
    0
    devnull has a little shameless behaviour in the past

      0  

    Default


    Good idea with all of that.
    As I hinted at in the original post, I started borrowing things from formPanel as well, and it may make sense to bring even more over. In the end it seems even more intuitive to think of a propertyGrid as just a form that has been rendered differently.
    My grid does already have an 'editable' config option, it really wouldnt take much to add methods to control this after render. This property is already implemented differently than the field 'editable' config, so changing its status would not affect the individual field statuses.

  4. #4
    Ext User
    Join Date
    Jul 2007
    Location
    Florida
    Posts
    9,996
    Vote Rating
    6
    mjlecomte will become famous soon enough mjlecomte will become famous soon enough

      0  

    Default


    I came across this older thread and am just passing the reference along:
    http://extjs.com/forum/showthread.ph...818#post136818

    I don't know what your version or the linked one does or does not do. Hopefully more people will add to the repository so it's easier to find all these resources.

  5. #5
    Ext User
    Join Date
    Jul 2007
    Posts
    3,128
    Vote Rating
    0
    devnull has a little shameless behaviour in the past

      0  

    Default


    Quite simply mine is just an attempt to make it behave more like a normal grid due to confusion on my part when I first started using it. Hopefully this allows people that are familiar with normal grids to use that experience when it comes to the property grid.
    And yeah, was kinda waiting for the repository thing to mature, and I think it is at that point now so I should get my stuff put in there

  6. #6
    Ext JS Premium Member
    Join Date
    Nov 2007
    Location
    Cambridge UK
    Posts
    112
    Vote Rating
    0
    hat27533 is on a distinguished road

      0  

    Default To make the entire grid read only :-

    To make the entire grid read only :-


    Nice...

    I know this is an old posting, however, I have found that to make the entire 'out of the box' PropertyGrid read only all you need to do is just cancel the onClick event :-

    Code:
    onClick:function(e){
         e.cancel = true;
             return false;
        },
    This works with 2.1 and 2.2 version

  7. #7
    Ext User
    Join Date
    Sep 2008
    Posts
    21
    Vote Rating
    0
    neo4200 is on a distinguished road

      0  

    Default


    Just want to say that this is a pretty nice extension.

  8. #8
    Ext User
    Join Date
    Sep 2008
    Posts
    21
    Vote Rating
    0
    neo4200 is on a distinguished road

      0  

    Default


    I had to make a little change in the setSource method, without that change the TextFields are initialized with &nbsp;

    Code:
     data.push(new Ext.grid.PropertyRecord({
    
                                    name: k.dataIndex,
    
                                    value: o[k.dataIndex]||"",
    
                                    header: k.header,
    
                                    field: k
    
                                }, k.id));

  9. #9
    Sencha User Remy's Avatar
    Join Date
    Apr 2008
    Posts
    298
    Vote Rating
    0
    Remy is on a distinguished road

      0  

    Default


    Anyone managed to use a checkboxgroup in this improved propertyGrid or the vanilla one? Can't think of the best way to present it? Maybe a multi-select combo would be the best approach as it wouldn't interfere with the UI? I have various bitwise fields in my DB for storing options but this single field needs to be rendered/edited as a multi-field list of sorts. Anyone have any experience in this area or ideas?

    Just realised Saki's LOVCombo would fit nicely with this. Would still welcome other suggestions/thoughts.
    Last edited by Remy; 24 Nov 2008 at 12:42 PM. Reason: Update on Saki's UX

  10. #10
    Sencha User Remy's Avatar
    Join Date
    Apr 2008
    Posts
    298
    Vote Rating
    0
    Remy is on a distinguished road

      0  

    Default


    I'm trying to integrate Saki's LOVCombo with this and am hitting a wall, I have dropped down to a standard combo to see if I can resolve it.

    I have the editor set to combo and the store retrieves the records and properly highlights the selected item when the combo is selected but I can't figure out how to get the displayField working properly. The field itself always displays the value that is selected. Is this because the combo is the 'editor' but I need something else as the renderer?

    I am using the remoteComponent plugin to retrieve the following JSON which instantiates my propertyGrid:

    Code:
    [
        {
            xtype: 'propertygrid2',
            id: 'propGrid',
            autoHeight: true,
            autoWidth: true,
            fields : [
                {
                    id: 'dd_id',
                    dataIndex: 'dd_id',
                    header: 'ID',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.NumberField({
                        selectOnFocus: true,
                        style: 'text-align: left;'
                    }))
                },
                {
                    id: 'dd_table',
                    dataIndex: 'dd_table',
                    header: 'Table',
                    editable: true
                },
                {
                    id: 'dd_field_id',
                    dataIndex: 'dd_field_id',
                    header: 'Field ID',
                    editable: true
                },
                {
                    id: 'dd_Desc',
                    dataIndex: 'dd_Desc',
                    header: 'Description',
                    editable: true
                },
                {
                    id: 'dd_Width',
                    dataIndex: 'dd_Width',
                    header: 'Field width',
                    editable: true
                },
                {
                    id: 'dd_lookup_field',
                    dataIndex: 'dd_lookup_field',
                    header: 'Lookup ID',
                    editable: true
                },
                {
                    id: 'dd_lookup_display',
                    dataIndex: 'dd_lookup_display',
                    header: 'Lookup Display',
                    editable: true
                },
                {
                    id: 'combodd_password',
                    dataIndex: 'dd_password',
                    header: 'Password',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.NumberField({
                        selectOnFocus: true,
                        style: 'text-align: left;'
                    }))
                },
                {
                    id: 'dd_default_value',
                    dataIndex: 'dd_default_value',
                    header: 'Default Value',
                    editable: true
                },
                {
                    id: 'dd_validation',
                    dataIndex: 'dd_validation',
                    header: 'Validation Code',
                    editable: true
                },
                {
                    id: 'dd_ValDesc',
                    dataIndex: 'dd_ValDesc',
                    header: 'Validation Desc.',
                    editable: true
                },
                {
                    id: 'combodd_method',
                    dataIndex: 'dd_method',
                    header: 'Method',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.NumberField({
                        selectOnFocus: true,
                        style: 'text-align: left;'
                    }))
                },
                {
                    id: 'combodd_view',
                    dataIndex: 'dd_view',
                    header: 'View Perm',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.ComboBox({
                        id: 'lovdd_view',
                        store: new Ext.data.JsonStore({
                            id: 'lovdd_view',
                            autoLoad: true,
                            mode: 'remote',
                            baseParams: {
                                table: 'DataPermissions',
                                primaryKey: 'dd_field_id',
                                lookupSourceField: 'dd_view',
                                lookupSourceFieldValue: '63',
                                lookupField: 'dp_id',
                                lookupValue: 'dp_desc',
                                readOnly: 'false'
                            },
                            url: 'ajax/FieldLookupList.asp',
                            root: 'rows',
                            fields: [
                                {
                                    name: 'dp_id',
                                    mapping: 'dp_id'
                                },
                                {
                                    name: 'LookupDisplay'
                                }
                            ]
                        }),
                        listeners: {
                            render: {
                                single: true,
                                fn: function(combo) {
                                    combo.store.on('load',
                                    function() {
                                        combo.setValue(63)
                                    },
                                    {
                                        single: true
                                    });combo.store.load();
                                }
                            }
                        },
                        displayField: 'LookupDisplay',
                        valueField: 'dp_id',
                        hideOnSelect: false,
                        triggerAction: 'all',
                        hiddenName: 'dd_view'
                    }))
                },
                {
                    id: 'combodd_add',
                    dataIndex: 'dd_add',
                    header: 'Add Perm',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.ComboBox({
                        id: 'lovdd_add',
                        store: new Ext.data.JsonStore({
                            id: 'lovdd_add',
                            autoLoad: true,
                            mode: 'remote',
                            baseParams: {
                                table: 'DataPermissions',
                                primaryKey: 'dd_field_id',
                                lookupSourceField: 'dd_add',
                                lookupSourceFieldValue: '63',
                                lookupField: 'dp_id',
                                lookupValue: 'dp_desc',
                                readOnly: 'false'
                            },
                            url: 'ajax/FieldLookupList.asp',
                            root: 'rows',
                            fields: [
                                {
                                    name: 'dp_id',
                                    mapping: 'dp_id'
                                },
                                {
                                    name: 'LookupDisplay'
                                }
                            ]
                        }),
                        listeners: {
                            render: {
                                single: true,
                                fn: function(combo) {
                                    combo.store.on('load',
                                    function() {
                                        combo.setValue(63)
                                    },
                                    {
                                        single: true
                                    });combo.store.load();
                                }
                            }
                        },
                        displayField: 'LookupDisplay',
                        valueField: 'dp_id',
                        hideOnSelect: false,
                        triggerAction: 'all',
                        hiddenName: 'dd_add'
                    }))
                },
                {
                    id: 'combodd_mod',
                    dataIndex: 'dd_mod',
                    header: 'Mod Perm',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.ComboBox({
                        id: 'lovdd_mod',
                        store: new Ext.data.JsonStore({
                            id: 'lovdd_mod',
                            autoLoad: true,
                            mode: 'remote',
                            baseParams: {
                                table: 'DataPermissions',
                                primaryKey: 'dd_field_id',
                                lookupSourceField: 'dd_mod',
                                lookupSourceFieldValue: '63',
                                lookupField: 'dp_id',
                                lookupValue: 'dp_desc',
                                readOnly: 'false'
                            },
                            url: 'ajax/FieldLookupList.asp',
                            root: 'rows',
                            fields: [
                                {
                                    name: 'dp_id',
                                    mapping: 'dp_id'
                                },
                                {
                                    name: 'LookupDisplay'
                                }
                            ]
                        }),
                        listeners: {
                            render: {
                                single: true,
                                fn: function(combo) {
                                    combo.store.on('load',
                                    function() {
                                        combo.setValue(63)
                                    },
                                    {
                                        single: true
                                    });combo.store.load();
                                }
                            }
                        },
                        displayField: 'LookupDisplay',
                        valueField: 'dp_id',
                        hideOnSelect: false,
                        triggerAction: 'all',
                        hiddenName: 'dd_mod'
                    }))
                },
                {
                    id: 'combodd_del',
                    dataIndex: 'dd_del',
                    header: 'Del Perm',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.ComboBox({
                        id: 'lovdd_del',
                        store: new Ext.data.JsonStore({
                            id: 'lovdd_del',
                            autoLoad: true,
                            mode: 'remote',
                            baseParams: {
                                table: 'DataPermissions',
                                primaryKey: 'dd_field_id',
                                lookupSourceField: 'dd_del',
                                lookupSourceFieldValue: '63',
                                lookupField: 'dp_id',
                                lookupValue: 'dp_desc',
                                readOnly: 'false'
                            },
                            url: 'ajax/FieldLookupList.asp',
                            root: 'rows',
                            fields: [
                                {
                                    name: 'dp_id',
                                    mapping: 'dp_id'
                                },
                                {
                                    name: 'LookupDisplay'
                                }
                            ]
                        }),
                        listeners: {
                            render: {
                                single: true,
                                fn: function(combo) {
                                    combo.store.on('load',
                                    function() {
                                        combo.setValue(63)
                                    },
                                    {
                                        single: true
                                    });combo.store.load();
                                }
                            }
                        },
                        displayField: 'LookupDisplay',
                        valueField: 'dp_id',
                        hideOnSelect: false,
                        triggerAction: 'all',
                        hiddenName: 'dd_del'
                    }))
                },
                {
                    id: 'combodd_Report',
                    dataIndex: 'dd_Report',
                    header: 'Report',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.ComboBox({
                        id: 'lovdd_Report',
                        store: new Ext.data.JsonStore({
                            id: 'lovdd_Report',
                            autoLoad: true,
                            mode: 'remote',
                            baseParams: {
                                table: 'DataPermissions',
                                primaryKey: 'dd_field_id',
                                lookupSourceField: 'dd_Report',
                                lookupSourceFieldValue: '63',
                                lookupField: 'dp_id',
                                lookupValue: 'dp_desc',
                                readOnly: 'false'
                            },
                            url: 'ajax/FieldLookupList.asp',
                            root: 'rows',
                            fields: [
                                {
                                    name: 'dp_id',
                                    mapping: 'dp_id'
                                },
                                {
                                    name: 'LookupDisplay'
                                }
                            ]
                        }),
                        listeners: {
                            render: {
                                single: true,
                                fn: function(combo) {
                                    combo.store.on('load',
                                    function() {
                                        combo.setValue(63)
                                    },
                                    {
                                        single: true
                                    });combo.store.load();
                                }
                            }
                        },
                        displayField: 'LookupDisplay',
                        valueField: 'dp_id',
                        hideOnSelect: false,
                        triggerAction: 'all',
                        hiddenName: 'dd_Report'
                    }))
                },
                {
                    id: 'dd_Report_XRef',
                    dataIndex: 'dd_Report_XRef',
                    header: 'Report Xref',
                    editable: true
                },
                {
                    id: 'dd_Lookup_XRef',
                    dataIndex: 'dd_Lookup_XRef',
                    header: 'Lookup XRef',
                    editable: true
                },
                {
                    id: 'combodd_Xref_Join',
                    dataIndex: 'dd_Xref_Join',
                    header: 'Xref Data Join',
                    editable: true,
                    editor: new Ext.grid.GridEditor(new Ext.form.NumberField({
                        selectOnFocus: true,
                        style: 'text-align: left;'
                    }))
                },
                {
                    id: 'dd_Xref2',
                    dataIndex: 'dd_Xref2',
                    header: 'Xref2',
                    editable: true
                },
                {
                    id: 'dd_Linked_Field',
                    dataIndex: 'dd_Linked_Field',
                    header: 'Linked Field',
                    editable: true
                }
            ],
            source: {
                
            }
        }
    ]
    Any help is appreciated.