PDA

View Full Version : [3.x] Ext.grid.ComboColumn & Ext.util.Format.comboRenderer



mjlecomte
4 May 2009, 6:18 PM
People love and hate putting combo's into grids. I think adding this render and an associated column xtype would be quite popular.

The example below needs this feature request:
http://extjs.com/forum/showthread.php?t=67485

The code below can almost be entirely sent across the wire via json config. The hanging chad is the column model, which just needs this feature request (adjustment needed to send defaults for column model):
http://extjs.com/forum/showthread.php?t=66340




<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>Grid Combo Renderer with xtypes</title>

<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-detail.js"></script>

<script type="text/javascript">

Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';

// create reusable renderer for ComboBox
Ext.util.Format.comboRenderer = function(combo){
return function(value){
var record = combo.findRecord(combo.valueField || combo.displayField, value);
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
}
}

/**
* @class Ext.grid.ComboColumn
* @extends Ext.grid.Column
* <p>A Column definition class which renders a ComboBox field based on the Column's configured
* editor. See the {@link Ext.grid.ColumnModel#xtype xtype} config option of {@link Ext.grid.ColumnModel}
* for more details.</p>
*/
Ext.grid.ComboColumn = Ext.extend(Ext.grid.Column, {
constructor: function(cfg){
Ext.grid.ComboColumn.superclass.constructor.call(this, cfg);
this.renderer = Ext.util.Format.comboRenderer(this.editor.field ? this.editor.field : this.editor);
}
});

// apply the custom column type to the prototype
Ext.apply(Ext.grid.Column.types, {
combocolumn: Ext.grid.ComboColumn
});


Ext.onReady(function(){

Ext.QuickTips.init();

// example of custom renderer function
function change(val){
if(val > 0){
return '<span style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '</span>';
}
return val;
}

// example of custom renderer function
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}

// create the combo instance
var combo = {
xtype: 'combo',
typeAhead: true,
triggerAction: 'all',
forceSelection: true,
selectOnFocus:true,
lazyRender:true,
mode: 'local',
valueNotFoundText:'Select Industry...',
store: {
xtype: 'arraystore',
id: 0,
fields: [
'myId',
'displayText'
],
data: [
[ 1, "Food"],
[ 2, "Retail"],
[ 3, "Aerospace"],
[ 4, "Communications"],
[ 5, "Construction"],
[ 5, "Finance"]
]
},
valueField: 'myId',
displayField: 'displayText'
};

var myData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am',1],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am',2],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am',2],
['American Express Company',52.55,0.01,0.02,'9/1 12:00am',2],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am',2],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am',4],
['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am',3],
['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am',5],
['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am',6],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
];

// create the data store
var store = {
xtype: 'arraystore',
autoDestroy: true,
data: myData,
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
{name: 'industry'}
]
};

// the column model has information about grid columns
// dataIndex maps the column to the specific data field in
// the data store (created below)
var colModel = new Ext.grid.ColumnModel({
columns: [
{id:'company',header: "Company", width: 160, dataIndex: 'company'},
{header: "Price", renderer: 'usMoney', dataIndex: 'price'},
{header: "Change", renderer: change, dataIndex: 'change'},
{header: "% Change", renderer: pctChange, dataIndex: 'pctChange'},
{
header: "Last Updated",
dataIndex: 'lastChange',
width: 85,
sortable: false,
//renderer: Ext.util.Format.dateRenderer('m/d/Y'),
xtype: 'datecolumn', // use xtype instead of renderer
format: 'M/d/Y' // config for datecolumn xtype
},{
header: "Industry",
dataIndex: 'industry',
width: 100,
editor: combo, // specify reference to combo instance
//renderer: Ext.util.Format.comboRenderer(combo) // pass combo instance to reusable renderer
xtype: 'combocolumn'
}
],
defaults: {
sortable: true, // by default columns are sortable
menuDisabled: true,
width: 75
}
});

// create the editor grid
var grid = new Ext.grid.EditorGridPanel({
store: store,
cm: colModel,
renderTo: document.body,
width: 600,
height: 300,
autoExpandColumn: 'company',
title:'Editable Array Grid',
frame:true,
clicksToEdit:1,
stripeRows: true,
tbar: [{
text: 'Add Company',
handler : function(){
var c = new grid.store.recordType({
company: 'New Company 1',
price: 0,
change: 0,
pctChange: 0,
lastChange: (new Date()).clearTime(),
industry: null
});
grid.stopEditing();
grid.store.insert(0, c);
grid.startEditing(0, 0);
}
}]
});

});
</script>

</head>
<body></body>
</html>

Condor
4 May 2009, 10:10 PM
Some additions:
1. Support comboboxes without valueField.
2. Support grid editors with a combobox field.


Ext.util.Format.comboRenderer = function(combo){
return function(value){
var record = combo.findRecord(combo.valueField || combo.displayField, value);
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
}
}

Ext.grid.ComboColumn = Ext.extend(Ext.grid.Column, {
constructor: function(cfg){
Ext.grid.ComboColumn.superclass.constructor.call(this, cfg);
this.renderer = Ext.util.Format.comboRenderer(this.editor.field ? this.editor.field : this.editor);
}
});

(these changes have been merged in post #1)

mjlecomte
19 May 2009, 5:08 AM
Someone asked about using this for Ext 2.2.1. I've modified the code posted above to work with 2.2.1:


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>Grid Combo Renderer</title>

<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />

<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>

<script type="text/javascript">

Ext.BLANK_IMAGE_URL = '../../resources/images/default/s.gif';

// create reusable renderer for ComboBox
Ext.util.Format.comboRenderer = function(combo){
return function(value){
var record = combo.findRecord(combo.valueField, value);
return record ? record.get(combo.displayField) : combo.valueNotFoundText;
}
}

/**
* @class Ext.grid.ComboColumn
* @extends Ext.grid.Column
* <p>A Column definition class which renders a ComboBox field based on the Column's configured
* editor. See the {@link Ext.grid.ColumnModel#xtype xtype} config option of {@link Ext.grid.ColumnModel}
* for more details.</p>
*/
/*
Ext.grid.ComboColumn = Ext.extend(Ext.grid.Column, {
constructor: function(cfg){
this.supr().constructor.apply(this, arguments);
this.renderer = Ext.util.Format.comboRenderer(this.editor);
}
});

// apply the custom column type to the prototype
Ext.apply(Ext.grid.Column.types, {
combocolumn: Ext.grid.ComboColumn
});
*/

Ext.onReady(function(){

Ext.QuickTips.init();

// example of custom renderer function
function change(val){
if(val > 0){
return '<span style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '</span>';
}
return val;
}

// example of custom renderer function
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}

// create the combo instance
var combo = new Ext.form.ComboBox({
//xtype: 'combo',
typeAhead: true,
triggerAction: 'all',
forceSelection: true,
selectOnFocus:true,
lazyRender:true,
mode: 'local',
valueNotFoundText:'Select Industry...',
store: new Ext.data.SimpleStore({
//xtype: 'arraystore',
id: 0,
fields: [
'myId',
'displayText'
],
data: [
[ 1, "Food"],
[ 2, "Retail"],
[ 3, "Aerospace"],
[ 4, "Communications"],
[ 5, "Construction"],
[ 5, "Finance"]
]
}),
valueField: 'myId',
displayField: 'displayText'
});

var myData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am',1],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am',2],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am',2],
['American Express Company',52.55,0.01,0.02,'9/1 12:00am',2],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am',2],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am',4],
['Boeing Co.',75.43,0.53,0.71,'9/1 12:00am',3],
['Caterpillar Inc.',67.27,0.92,1.39,'9/1 12:00am',5],
['Citigroup, Inc.',49.37,0.02,0.04,'9/1 12:00am',6],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am'],
['Exxon Mobil Corp',68.1,-0.43,-0.64,'9/1 12:00am'],
['General Electric Company',34.14,-0.08,-0.23,'9/1 12:00am'],
['General Motors Corporation',30.27,1.09,3.74,'9/1 12:00am'],
['Hewlett-Packard Co.',36.53,-0.03,-0.08,'9/1 12:00am'],
['Honeywell Intl Inc',38.77,0.05,0.13,'9/1 12:00am'],
['Intel Corporation',19.88,0.31,1.58,'9/1 12:00am'],
['International Business Machines',81.41,0.44,0.54,'9/1 12:00am'],
['Johnson & Johnson',64.72,0.06,0.09,'9/1 12:00am'],
['JP Morgan & Chase & Co',45.73,0.07,0.15,'9/1 12:00am'],
['McDonald\'s Corporation',36.76,0.86,2.40,'9/1 12:00am'],
['Merck & Co., Inc.',40.96,0.41,1.01,'9/1 12:00am'],
['Microsoft Corporation',25.84,0.14,0.54,'9/1 12:00am'],
['Pfizer Inc',27.96,0.4,1.45,'9/1 12:00am'],
['The Coca-Cola Company',45.07,0.26,0.58,'9/1 12:00am'],
['The Home Depot, Inc.',34.64,0.35,1.02,'9/1 12:00am'],
['The Procter & Gamble Company',61.91,0.01,0.02,'9/1 12:00am'],
['United Technologies Corporation',63.26,0.55,0.88,'9/1 12:00am'],
['Verizon Communications',35.57,0.39,1.11,'9/1 12:00am'],
['Wal-Mart Stores, Inc.',45.45,0.73,1.63,'9/1 12:00am']
];

// create the data store
var store = new Ext.data.SimpleStore({
//xtype: 'arraystore',
autoDestroy: true,
data: myData,
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
{name: 'industry'}
]
});

// the column model has information about grid columns
// dataIndex maps the column to the specific data field in
// the data store (created below)
var colModel = new Ext.grid.ColumnModel({
columns: [
{id:'company',header: "Company", width: 160, dataIndex: 'company'},
{header: "Price", renderer: 'usMoney', dataIndex: 'price'},
{header: "Change", renderer: change, dataIndex: 'change'},
{header: "% Change", renderer: pctChange, dataIndex: 'pctChange'},
{
header: "Last Updated",
dataIndex: 'lastChange',
width: 85,
sortable: false,
//renderer: Ext.util.Format.dateRenderer('m/d/Y'),
xtype: 'datecolumn', // use xtype instead of renderer
format: 'M/d/Y' // config for datecolumn xtype
},{
header: "Industry",
dataIndex: 'industry',
width: 100,
editor: combo, // specify reference to combo instance
renderer: Ext.util.Format.comboRenderer(combo) // pass combo instance to reusable renderer
//xtype: 'combocolumn'
}
],
defaults: {
sortable: true, // by default columns are sortable
menuDisabled: true,
width: 75
}
});

// create the editor grid
var grid = new Ext.grid.EditorGridPanel({
store: store,
cm: colModel,
renderTo: document.body,
width: 600,
height: 300,
autoExpandColumn: 'company',
title:'Editable Array Grid',
frame:true,
clicksToEdit:1,
stripeRows: true,
tbar: [{
text: 'Add Company',
handler : function(){
var c = new grid.store.recordType({
company: 'New Company 1',
price: 0,
change: 0,
pctChange: 0,
lastChange: (new Date()).clearTime(),
industry: null
});
grid.stopEditing();
grid.store.insert(0, c);
grid.startEditing(0, 0);
}
}]
});

});
</script>

</head>
<body></body>
</html>