PDA

View Full Version : PropertyGrid ComboBox: displayField & valueField



suamikim
22 Aug 2012, 6:09 AM
Hi there,

i'm using a propertygrid with a custom editor of type combobox. The problem i'm experiencing is that the value i set for displayField (Value1, Value2, Value3) only gets displayed after the editor of the combobox is actually openened. In the standard view the property-grid shows the value defined as fieldValue (1, 2, 3):

http://jsfiddle.net/suamikim/EznUc/

Ext.onReady(function() {
Ext.create('Ext.window.Window', {
width: 300,
height: 200,
layout: 'fit',
items: [{
xtype: 'propertygrid',

customEditors: {
CustomValue: {
xtype: 'combo',
store: {
fields: ['display', 'value'],
data: [
{ 'display': 'Value1', 'value': 1 },
{ 'display': 'Value2', 'value': 2 },
{ 'display': 'Value3', 'value': 3 }
]
},
queryMode: 'local',
displayField: 'display',
valueField: 'value',
editable: false
}
},

source: {
"CustomValue": 2
}
}]
}).show();
});

Is there a way to always show the display value (Value1, Value2, Value3)?

Thanks,

mike

droessner
22 Aug 2012, 11:55 AM
You'll need to add a customRenderer for that field as well.

http://docs.sencha.com/ext-js/4-1/#!/api/Ext.grid.property.Grid-cfg-customRenderers

scottmartin
22 Aug 2012, 1:13 PM
The following should work:




customRenderers: {
CustomValue: function(v) {
store.findBy(function(record) {
if (record.get('value') === v) {
v = record.get('display');
return true; // findby
}
});
return v;
}
}


Scott

suamikim
22 Aug 2012, 10:58 PM
Ok, the customRenderers are exactely what i was looking for, so thanks for that!

Unfortunately my problems are not totally solved with this. Actually i don't have only 1 custom combobox editor but many of them. Therefore the custom-renderer-function needs to be as generic as possible.

The best solution i can think of is to make an own class for the custom combobox editor which looks something like this:

// New PropertyGridEditor with functionality to render the selected value correctely to the grid
Ext.define('PropertyGridComboBoxEditor', {
extend: 'Ext.form.ComboBox',

// set some default values
queryMode: 'local',
displayField: 'type',
valueField: 'value',
editable: false,

// constructor
constructor: function(config) {
this.initConfig(config);

// apply the data-object to the store if it was given with the config
if (config.data && config.data[0]) {
this.store = Ext.create('Ext.data.Store', {
fields: ['type', 'value'],
data: config.data
});
}

return this.callParent(arguments);
},

// Generic custom renderer function
renderer: function(value, meta, record, rowIdx, colIdx, store, view) {
// !!! "this" is the scope of the grid -> we're working on the wrong store !!!
this.store.findBy(function(r) {
if (r.get('value') === value) {
value = r.get('type');
return true; // findby
}
});

return value;
}
});

As you can see, this class provides a function "renderer" which would handle the custom rendering. Unfortunately i'm not able to control the scope (or at leat don't know how...) in which this function gets called and therefore have no access to the correct store to get the display value ("type" in this case...).

The usage of this custom class looks like this:

Ext.onReady(function() {
var customEditors = [],
customRenderers = [];

// create custom editor & renderer for property "Visibility"
customEditors['Visibility'] = Ext.create('PropertyGridComboBoxEditor', {
data: [
{ 'type': 'Show', 'value': '0' },
{ 'type': 'Hide', 'value': '1' },
{ 'type': 'Readonly', 'value': '2' },
{ 'type': 'Pluged out', 'value': '3' }
]
});
customRenderers['Visibility'] = customEditors['Visibility'].renderer;

// create custom editor & renderer for property "Alignment"
customEditors['Alignment'] = Ext.create('PropertyGridComboBoxEditor', {
data: [
{ 'type': 'Left', 'value': '0' },
{ 'type': 'Right', 'value': '1' },
{ 'type': 'Top', 'value': '2' },
{ 'type': 'Bottom', 'value': '3' }
]
});
customRenderers['Alignment'] = customEditors['Alignment'].renderer;

// Create a window with the propertygrid
Ext.create('Ext.window.Window', {
width: 300,
height: 200,
layout: 'fit',
items: [{
xtype: 'propertygrid',

customEditors: customEditors,
customRenderers: customRenderers,

source: {
"Visibility": 2,
"Alignment": 3
}
}]
}).show();
});

A complete example is on jsfiddle again:
http://jsfiddle.net/suamikim/EznUc/1/

I'd really appreciate every input. Either if it would be how to control the scope of the renderer-function or any other completely different approach to keep the custom renderer as generic as possible!

Thanks

droessner
23 Aug 2012, 6:18 AM
You can throw your renderer function into the constructor function so that you have the right store reference. Something like this:



Ext.define('PropertyGridComboBoxEditor', {
extend: 'Ext.form.ComboBox',


// set some default values
queryMode: 'local',
displayField: 'type',
valueField: 'value',
editable: false,


// constructor
constructor: function(config) {
var me = this;


this.initConfig(config);


// apply the data-object to the store if it was given with the config
if (config.data && config.data[0]) {
me.store = Ext.create('Ext.data.Store', {
fields: ['type', 'value'],
data: config.data
});
}


// Generic custom renderer function
me.renderer = function(value, meta, record, rowIdx, colIdx, store, view) {
var record = me.store.findRecord('value', value);


if (record) {
value = record.get('type');
}


return value;
};


return this.callParent(arguments);
}
});

suamikim
23 Aug 2012, 6:56 AM
Ok, we're almost there ;)

http://jsfiddle.net/suamikim/EznUc/2/

// New PropertyGridEditor with functionality to render the selected value correctely to the grid
Ext.define('PropertyGridComboBoxEditor', {
extend: 'Ext.form.ComboBox',

// set some default values
queryMode: 'local',
displayField: 'type',
valueField: 'value',
editable: false,

// constructor
constructor: function(config) {
var me = this;

this.initConfig(config);

// apply the data-object to the store if it was given with the config
if (config.data && config.data[0]) {
this.store = Ext.create('Ext.data.Store', {
fields: ['type', 'value'],
data: config.data
});
}

// Generic custom renderer function
this.renderer = function(value, meta, record, rowIdx, colIdx, store, view) {
var idx = me.store.find('value', value);

return (idx >= 0) ? (me.store.getAt(idx).get('type')) : value;
};

return this.callParent(arguments);
}
});

Ext.onReady(function() {
var customEditors = [],
customRenderers = [];

// create custom editor & renderer for property "Visibility"
customEditors['Visibility'] = Ext.create('PropertyGridComboBoxEditor', {
data: [
{ 'type': 'Show', 'value': '0' },
{ 'type': 'Hide', 'value': '1' },
{ 'type': 'Readonly', 'value': '2' },
{ 'type': 'Pluged out', 'value': '3' }
]
});
customRenderers['Visibility'] = customEditors['Visibility'].renderer;

// create custom editor & renderer for property "Alignment"
customEditors['Alignment'] = Ext.create('PropertyGridComboBoxEditor', {
data: [
{ 'type': 'Left', 'value': '0' },
{ 'type': 'Right', 'value': '1' },
{ 'type': 'Top', 'value': '2' },
{ 'type': 'Bottom', 'value': '3' }
]
});
customRenderers['Alignment'] = customEditors['Alignment'].renderer;

// Create a window with the propertygrid
Ext.create('Ext.window.Window', {
width: 300,
height: 200,
layout: 'fit',
items: [{
xtype: 'propertygrid',

customEditors: customEditors,
customRenderers: customRenderers,

source: {
"Visibility": 2,
"Alignment": 3
}
}]
}).show();
});

It shows the correct display-value after initialisation but when you click at the value for the first time, the combobox does not open the list but instead shows the raw value. It shows the list after a second click and does not select the correct entry.

If you select a different value now from the list, close it and click on the value again, everything is working fine...

Thanks

droessner
23 Aug 2012, 7:00 AM
Just a type mismatch :)

Your store has the values as strings, but your source has them as numeric. You'll have to fix one or the other.

suamikim
23 Aug 2012, 9:46 PM
Perfect!

Thanks alot & best regards,

Mik