PDA

View Full Version : Improved PropertyGrid



devnull
15 Jul 2008, 3:03 PM
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:


[{
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:


/*
* 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(grid, source){
this.grid = grid;
this.store = new Ext.data.Store({
recordType : Ext.grid.PropertyRecord
});
this.store.loadRecords = function(o, options, success){
if(!o || success === false){
if(success !== false){
this.fireEvent("load", this, [], options);
}
if(options.callback){
options.callback.call(options.scope || this, [], options, false);
}
return;
}
var r = o.records, t = o.totalRecords || r.length;
if(!options || options.add !== true){
if(this.pruneModifiedRecords){
this.modified = [];
}
for(var i = 0, len = r.length; i < len; i++){
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(t, this.data.length+r.length);
this.add(r);
}
this.fireEvent("load", this, r, options);
if(options.callback){
options.callback.call(options.scope || this, r, options, true);
}
}
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.PropertyStore, Ext.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({
name: k.dataIndex,
value: o[k.dataIndex],
header: k.header,
field: k
}, k.id));
}
}
} else {
for (var k in o) {
if (this.isEditableValue(o[k])) {
data.push(new Ext.grid.PropertyRecord({
name: k,
value: o[k],
header: k
}, k));
}
}
}
this.store.loadRecords({records: data}, {}, true);
},

// private
onUpdate : function(ds, record, type){
if(type == Ext.data.Record.EDIT){
var v = record.data['value'];
var oldValue = record.modified['value'];
if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
this.source[record.id] = v;
record.commit();
this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
}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(prop, value){
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(grid, store){
this.grid = grid;
var g = Ext.grid;
Ext.ux.grid.PropertyColumnModel.superclass.constructor.call(this, [
{header: this.nameText, width:grid.nameWidth, sortable: true, dataIndex:'header', id: 'name', menuDisabled:true},
{header: this.valueText, width:grid.valueWidth, resizable:false, dataIndex: '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 f = Ext.form;

var bfield = new f.Field({
el:this.bselect,
bselect : this.bselect,
autoShow: true,
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:true, style:'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.PropertyColumnModel, Ext.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(colIndex, rowIndex){
var p = this.store.getProperty(rowIndex);
if (p.data.field && p.data.field.editable == false) {
return false;
}
return colIndex == 1;
},

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

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

// private
renderCell : function(val, metadata, record, rowIndex, colIndex, store){

if (record.data.field && typeof(record.data.field.renderer) == 'function'){
return record.data.field.renderer.call(this, val, metadata, record, rowIndex, colIndex, store);
}
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(colIndex, rowIndex){
var p = this.store.getProperty(rowIndex);
var n = 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,
trackMouseOver: false,
clicksToEdit:1,
enableHdMenu : false,
editable: true,
nameWidth: 50,
valueWidth: 50,
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(this, store);
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(sm, rowIndex, colIndex){
if(colIndex === 0){
this.startEditing.defer(200, this, [rowIndex, 1]);
return false;
}
}, this);
if (!this.editable){
this.on('beforeedit', function(){return false})
}
},

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

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

// private
afterRender: function(){
Ext.ux.grid.PropertyGrid.superclass.afterRender.apply(this, arguments);
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);

JEBriggs
16 Jul 2008, 8:27 AM
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:


cm.setEditable(1, false);

I found that I had to add the following to your PropertyGrid:


/**
* 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!

devnull
16 Jul 2008, 9:25 AM
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.

mjlecomte
11 Sep 2008, 3:05 PM
I came across this older thread and am just passing the reference along:
http://extjs.com/forum/showthread.php?p=136818#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. ;)

devnull
12 Sep 2008, 9:41 AM
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 :)

hat27533
28 Oct 2008, 4:09 AM
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 :-



onClick:function(e){
e.cancel = true;
return false;
},


This works with 2.1 and 2.2 version :)

neo4200
4 Nov 2008, 7:02 AM
Just want to say that this is a pretty nice extension.

neo4200
5 Nov 2008, 1:10 AM
I had to make a little change in the setSource method, without that change the TextFields are initialized with &nbsp;



data.push(new Ext.grid.PropertyRecord({

name: k.dataIndex,

value: o[k.dataIndex]||"",

header: k.header,

field: k

}, k.id));

Remy
24 Nov 2008, 12:37 PM
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 (http://extjs.com/forum/showthread.php?p=154101#post154101) would fit nicely with this. Would still welcome other suggestions/thoughts.

Remy
25 Nov 2008, 11:50 AM
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:


[
{
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.

Remy
26 Nov 2008, 2:02 AM
A bit more digging around and I do need a renderer to show the displayField attributes, I had my test rendering function within the wrong braces and at least I know its functioning now. Anyone have any hints on debugging using Firebug when you are eval'ing ajax responses? This is making it mighty tricky to debug. At the moment I am taking my rendered response, running through JSONLint.com and viewing the results, not debugging per se but the easiest way I can think of showing the full results. Its like debugging someone else's code (:|

mjlecomte
26 Nov 2008, 6:14 AM
Anyone have any hints on debugging using Firebug when you are eval'ing ajax responses? This is making it mighty tricky to debug.
Deserving of it's own thread. I just hit this myself. Maybe post a different thread for it. One way around this might be adding the source to the head instead of eval'ing it. I'm still using Firebug 1.05, maybe newer versions handle it better?

mjlecomte
13 Dec 2008, 5:44 PM
Anyone have any hints on debugging using Firebug when you are eval'ing ajax responses?

Came across something that would help with this (aside from using script that you can toggle to instead of eval'ing you append the source code to the document head element):
http://www.almaden.ibm.com/u/bartonjj/fireclipse/index.html

dsonet
27 Mar 2009, 3:12 AM
/*
* Ext JS Library 2.2
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
/**
* @class Ext.grid.PropertyRecord
* @modifier: DSONet (dsonet@msn.com)
* 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.ds.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.grid.PropertyRecord = Ext.data.Record.create([
{name:'name',type:'string'}, 'value', "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.grid.PropertyStore = function(grid, source){
this.grid = grid;
this.store = new Ext.data.Store({
recordType : Ext.grid.PropertyRecord
});
this.store.on('update', this.onUpdate, this);
if(source){
this.setSource(source);
}
Ext.grid.PropertyStore.superclass.constructor.call(this);
};
Ext.extend(Ext.grid.PropertyStore, Ext.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 = [], l;
if (fields && (l = fields.length))
{
var i = -1, k, n;
while (++i < l)
{

k = fields[i];

if (typeof (k) == 'object' && (n = k.dataIndex || k.id) && this.isEditableValue(o[n]))
{
/*if(k.header)
this.grid.propertyNames[n] = k.header;
if(k.editor)
this.grid.customEditors[n] = k.editor;*/

data.push(new Ext.grid.PropertyRecord(
{
name: n,
value: o[n],
field: k
}, k.id || k.dataIndex));
}
}
}
else
{
for (var k in o)
{
if (this.isEditableValue(o[k]))
{
data.push(new Ext.grid.PropertyRecord(
{
name: k,
value: o[k]
}, k));
}
}
}
this.store.loadRecords({records: data}, {}, true);
},
// private
onUpdate : function(ds, record, type){
if(type == Ext.data.Record.EDIT){
var v = record.data['value'];
var oldValue = record.modified['value'];
if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
this.source[record.id] = v;
record.commit();
this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
}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(prop, value){
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.grid.PropertyColumnModel = function(grid, store){
this.grid = grid;
var g = Ext.grid;
g.PropertyColumnModel.superclass.constructor.call(this, [
{header: this.nameText, width: grid.nameWidth, sortable: true, dataIndex: 'name', id: 'name', menuDisabled: true},
{header: this.valueText, width: grid.valueWidth, resizable: false, dataIndex: '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 f = Ext.form;
var bfield = new f.Field({
el:this.bselect,
bselect : this.bselect,
autoShow: true,
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:true, style:'text-align:left;'})),
'boolean' : new g.GridEditor(bfield)
};
this.initialTypes = {};
this.renderCellDelegate = this.renderCell.createDelegate(this);
this.renderPropDelegate = this.renderProp.createDelegate(this);
};
Ext.extend(Ext.grid.PropertyColumnModel, Ext.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(colIndex, rowIndex){
var p = this.store.getProperty(rowIndex);
if (p.data.field && p.data.field.editable == false)
{
return false;
}
return colIndex == 1;
},
// private
getRenderer : function(col){
return col == 1 ?
this.renderCellDelegate : this.renderPropDelegate;
},
// private
renderProp : function(v, metadata, record){
var ref;
if ((ref = record.data.field) && typeof (ref.header) != 'undefined')
{
return ref.header;
}
var pn = this.grid.propertyNames;
return pn && pn[v] ? pn[v] : v;
//return this.getPropertyName(v);
},
// private
renderCell : function(val, metadata, record){//, rowIndex, colIndex, store
var ref;
if ((ref = record.data.field) && typeof (ref.renderer) == 'function')
{
return ref.renderer.apply(this, arguments);
}
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(colIndex, rowIndex){
var p = this.store.getProperty(rowIndex);
var n = p.data['name'], val = p.data['value'];
if (p.data.field && typeof (p.data.field.editor) == 'object')
{
return p.data.field.editor;
}
else if(this.grid.customEditors[n]){
return this.grid.customEditors[n];
}
var t = this.initialTypes[n];
if(t)
{
return this.editors[t];
}
if(Ext.isDate(val)){
t = "date";
}
else
{
var vt = typeof val;
switch(vt)
{
case "number":
case "boolean":
t = vt;break;
default:
t = "string";
}
}
this.initialTypes[n] = t;
return this.editors[t];
}
});
/**
* @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
*/
var PropertyGrid = Ext.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,
trackMouseOver: false,
clicksToEdit:1,
enableHdMenu : false,
editable: true,
nameWidth: 50,
valueWidth: 50,
autoExpandColumn: 'value',
viewConfig : {
forceFit:true
},
// private
initComponent : function(){
this.propertyNames = this.propertyNames || {};
this.customEditors = this.customEditors || {};
this.lastEditRow = null;
var store = new Ext.grid.PropertyStore(this);
this.propStore = store;
var cm = new Ext.grid.PropertyColumnModel(this, store);
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;
PropertyGrid.superclass.initComponent.call(this);
this.selModel.on('beforecellselect', function(sm, rowIndex, colIndex){
if(colIndex === 0){
this.startEditing.defer(200, this, [rowIndex, 1]);
return false;
}
}, this);
if (!this.editable)
{
this.on('beforeedit', Ext.falseFn);
}
},
// private
onRender : function(){
PropertyGrid.superclass.onRender.apply(this, arguments);
this.getGridEl().addClass('x-props-grid');
},
// private
afterRender: function(){
PropertyGrid.superclass.afterRender.apply(this, arguments);
if(this.source){
this.setSource(this.source, this.fields);
}
},
/**
* 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, fields){
this.propStore.setSource(source, fields);
},
/**
* 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("propertygrid", PropertyGrid);

somebee
26 Jul 2009, 5:10 AM
Fantastic extension! Any plans to make this compatible with Extjs 3.0?

Stju
15 Mar 2010, 2:01 AM
Plug & Play :)


/* http://www.extjs.com/forum/showthread.php?t=41390 */
Ext.namespace('Ext.ux.grid');
Ext.ux.grid.PropertyRecord = Ext.data.Record.create([
{name:'name',type:'string'}, 'value', 'header', 'field'
]);

Ext.ux.grid.PropertyStore = function(grid, source){
this.grid = grid;
this.store = new Ext.data.Store({
recordType : Ext.grid.PropertyRecord
});

this.store.loadRecords = function(o, options, success){
if(!o || success === false){
if(success !== false){
this.fireEvent("load", this, [], options);
}
if(options.callback){
options.callback.call(options.scope || this, [], options, false);
}
return;
}

var r = o.records, t = o.totalRecords || r.length;

if(!options || options.add !== true){
if(this.pruneModifiedRecords){
this.modified = [];
}

for(var i = 0, len = r.length; i < len; i++){
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(t, this.data.length+r.length);
this.add(r);
}

this.fireEvent("load", this, r, options);

if(options.callback){
options.callback.call(options.scope || this, r, options, true);
}
};

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.PropertyStore, Ext.util.Observable, {
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({
name: k.dataIndex,
value: o[k.dataIndex],
header: k.header,
field: k
}, k.id));
}
}
} else {
for (var k in o) {
if (this.isEditableValue(o[k])) {
data.push(new Ext.grid.PropertyRecord({
name: k,
value: o[k],
header: k
}, k));
}
}
}
this.store.loadRecords({records: data}, {}, true);
},

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

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

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

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

getSource : function(){
return this.source;
}
});

Ext.ux.grid.PropertyColumnModel = function(grid, store){
this.grid = grid;
var g = Ext.grid;
var f = Ext.form;
this.store = store;

Ext.ux.grid.PropertyColumnModel.superclass.constructor.call(this, [
{header: this.nameText, width:grid.nameWidth, fixed:true, sortable: true, dataIndex:'header', id: 'name', menuDisabled:true},
{header: this.valueText, width:grid.valueWidth, resizable:false, dataIndex: 'value', id: 'value', menuDisabled:true}
]);

this.booleanEditor = new Ext.form.ComboBox({
triggerAction : 'all',
mode : 'local',
valueField : 'boolValue',
displayField : 'name',
editable:false,
selectOnFocus: true,
forceSelection: true,
store : {
xtype : 'arraystore',
idIndex : 0,
fields : ['boolValue','name'],
data : [[false,'false'],[true,'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:true, style:'text-align:left;'})),
'boolean' : new g.GridEditor(this.booleanEditor)
};

this.renderCellDelegate = this.renderCell.createDelegate(this);
this.renderPropDelegate = this.renderProp.createDelegate(this);
};

Ext.extend(Ext.ux.grid.PropertyColumnModel, Ext.grid.ColumnModel, {
nameText : 'Name',
valueText : 'Value',
dateFormat : 'j/m/Y',

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

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

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

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

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

renderCell : function(val, metadata, record, rowIndex, colIndex, store){
if (record.data.field && typeof(record.data.field.renderer) == 'function'){
return record.data.field.renderer.call(this, val, metadata, record, rowIndex, colIndex, store);
}

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);
},

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

getCellEditor : function(colIndex, rowIndex){
var p = this.store.getProperty(rowIndex);
var n = 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'];
}
},

destroy : function(){
Ext.ux.grid.PropertyColumnModel.superclass.destroy.call(this);
for(var ed in this.editors){
Ext.destroy(this.editors[ed]);
}
}
});

Ext.ux.grid.PropertyGrid = Ext.extend(Ext.grid.EditorGridPanel, {
enableColumnMove:false,
stripeRows:false,
trackMouseOver: false,
clicksToEdit:1,
enableHdMenu : false,
editable: true,
nameWidth: 120,
valueWidth: 50,
source: {},
autoExpandColumn: 'value',

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(this, store);
store.store.sort('name', 'ASC');
this.addEvents(
'beforepropertychange',
'propertychange'
);
this.cm = cm;
this.ds = store.store;
Ext.ux.grid.PropertyGrid.superclass.initComponent.call(this);

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

onRender : function(){
Ext.ux.grid.PropertyGrid.superclass.onRender.apply(this, arguments);
this.getGridEl().addClass('x-props-grid');
},

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

setSource : function(source){
this.propStore.setSource(source,this.fields);
},

load : function(source){
this.setSource(source);
},

loadRecord : function(record) {
record.data && this.setSource(record.data);
},

getSource : function(){
return this.propStore.getSource();
},

setEditable: function(rowIndex, editable) {
var p = this.store.getProperty(rowIndex);
if(p.data.field) p.data.field.editable = editable;
}
});
Ext.reg("propertygrid2", Ext.ux.grid.PropertyGrid);

Jack_S
14 Sep 2010, 9:09 AM
Hello,

I've mostly only need this property grid as a full non-editable property grid. But now my would like to be able to do some updates to particular fields.

My only problem is that I'm unable to get the value e.field. I always get undefined. Can anybody help with this. I thought that the field was automatically derived from the name of the field?

Thanks

Jack

Here is my column declaration:


{
dataIndex: 'address',
header: 'Address',
editable: true
}


Here is my store fields:



,reader: new Ext.data.JsonReader({
root: 'results'
,id: 'cust_id'
,fields: [
{name: 'cust_id', type: 'int'}
,{name: 'first_name'}
,{name: 'address'}
,{name: 'city'}
,{name: 'state'}
,{name: 'country'}
]
})

Jack_S
16 Oct 2010, 7:03 PM
There seems to be problems with the custom editors:

Failing code example - try adding your own editor



,{
dataIndex: 'DATABASE_LOG_MODE'
,header: 'Log Mode'
//,editable: true
,editor: new Ext.form.ComboBox({
lazyRender: true
,triggerAction: 'all'
,store: new Ext.data.SimpleStore({
fields: ['id','text']
,data: [['ARCHIVELOG','ARCHIVELOG'],['NOARCHIVELOG','NOARCHIVELOG']]
})
,editable: false
,displayField: 'text'
,valueField: 'id'
,mode: 'local'
,typeAhead: false
,forceSelection: true
})
}


I caught this in Firebug, unfortunately, I don't knwo how to fix it.


ed.startEdit is not a function
ed.startEdit(this.view...rstChild, Ext.isDefined(v) ? v : '');
ext-all-debug.js (line 46905)
ae[cancel === true ? "cancelEdit" : "completeEdit"] is not a function
[Break on this error] ae[cancel === true ? 'cancelEdit' : 'completeEdit']();
ext-all-debug.js (line 46932)
ae.realign is not a function
[Break on this error] ae.realign(true);


Seems like the problem maybe related to :
http://www.sencha.com/forum/showthread.php?92950-FIXED-661-3.2.x-ed-startEdit%28%29-is-not-a-function
http://www.sencha.com/forum/showthread.php?92816-ed-startEdit%28%29-is-not-a-function

How to fix:
use :


{
dataIndex: 'DATABASE_LOG_MODE'
,header: 'Log Mode'
//,editable: true
,editor: [B]new Ext.grid.GridEditor(new Ext.form.ComboBox({
.......



Awesome ux.

Jack

hypergolic
25 Oct 2010, 6:53 PM
Thanks guys, the improved property grid is working great for me.

ttbgwt
16 Dec 2011, 6:52 PM
Do you have example using this extension, with a data store? I tried populating an array store and made sure the ids matched up, but the grid just doesnt get the data from the store. When the store load its data, do I have to manually load the property grid? Any samples would be greatly appreciated. Thanks