This page describes the process of dynamically creating a ExtJS columnModel based on data from a Ajax call. Generating a data Grid when the columns can not be predefined requires a different approach. The data coming from the server is evaluated and the columnModel is constructed in a set of if-else conditions. Once the column model and store have been initialized they are passed to the gridpanel for display.
Requirements
- Html Editor
- HTTP Server to serve the pages from
Procedure
Create the following html page:
Procedure:
- Make an Ajax request using the Standard XMLHttpRequest browser object.
- Read the meta-data from the response
- Run thru a series of if-else conditions to create and insert columns into the dynamic column model
- Feed the GridPanel with the store and the column model.
The following html file sets up the styles and imports the core JavaScript libraries.
index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Stateful + Dynamic Grid Panel with Grouping and Totals</title>
<!-- ** CSS ** -->
<!-- base library -->
<link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css" />
<!-- overrides to base library -->
<!-- page specific -->
<link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/examples/shared/examples.css" />
<style type=text/css>
/*!
* Ext JS Library 3.3.1
* Copyright(c) 2006-2010 Sencha Inc.
* licensing@sencha.com
* http://www.sencha.com/license
*/
#grid-example .x-grid-col-1 {
text-align: right;
}
#grid-example .x-grid-col-2{
text-align: right;
}
#grid-example .x-grid-col-3 {
text-align: right;
}
#grid-example .x-grid-col-4 {
text-align: right;
}
#grid-example.x-grid-mso{
border: 1px solid #6593cf;
}
#grid-example.x-grid-vista{
border: 1px solid #b3bcc0;
}
#xml-grid-example{
border: 1px solid #cbc7b8;
left: 0;
position: relative;
top: 0;
}
#editor-grid .x-grid-col-2{
text-align:right;
}
.x-grid3-td-topic b {
font-family:tahoma, verdana;
display:block;
}
.x-grid3-td-topic b i {
font-weight:normal;
font-style: normal;
color:#000;
}
.x-grid3-td-topic .x-grid3-cell-inner {
white-space:normal;
}
.x-grid3-td-topic a {
color: #385F95;
text-decoration:none;
}
.x-grid3-td-topic a:hover {
text-decoration:underline;
}
.details .x-btn-text {
background-image: url(details.gif);
}
.x-resizable-pinned .x-resizable-handle-south{
background:url(../../resources/images/default/sizer/s-handle-dark.gif);
background-position: top;
}
/* style rows on mouseover */
.x-grid3-row-over .x-grid3-cell-inner {
font-weight: bold;
}
/* style for the "buy" ActionColumn icon */
.x-action-col-cell img.buy-col {
height: 16px;
width: 16px;
background-image: url(../shared/icons/fam/accept.png);
}
/* style for the "alert" ActionColumn icon */
.x-action-col-cell img.alert-col {
height: 16px;
width: 16px;
background-image: url(../shared/icons/fam/error.png);
}
</style>
<!-- overrides to base library -->
<link rel="stylesheet" type="text/css" href="http://dev.sencha.com/deploy/ext-3.3.1/examples/ux/css/GroupSummary.css" />
<!-- ** Javascript ** -->
<!-- ExtJS library: base/adapter -->
<script type="text/javascript"
src="http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base-debug.js">
</script>
<script type="text/javascript"
src="http://dev.sencha.com/deploy/ext-3.3.1/ext-all-debug.js">
</script>
<!-- overrides to base library -->
<!-- extensions -->
<script type="text/javascript" src="http://dev.sencha.com/deploy/ext-3.3.1/examples/ux/GroupSummary.js"></script>
<!-- page specific -->
<script type="text/javascript" src="array-grid.js"></script>
</head>
<body>
<h1>Stateful + Dynamic Grid Panel with Grouping and Totals</h1>
<p>Note that the js is not minified so it is readable. See <a href="array-grid.js">array-grid.js</a>.</p>
<div id="grid-example2"></div>
</body>
</html>
array-grid.js
Ext.onReady(function(){
Ext.QuickTips.init();
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
// The columns are constructed dynamically here
// Ext.Ajax.request() introduces timing issues since it is asynchronous.
// use XMLHttpRequest since it is synchronous in nature.
var xmlhttp = {};
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET",'response1.do',false); // make a synchronous request
xmlhttp.send(null);
var prefs = {};
if(xmlhttp.status == 200) {
var ajaxReader = new Ext.data.JsonReader();
var ajaxStore = new Ext.data.GroupingStore({
groupField:'industry',
reader: ajaxReader,
data: Ext.decode(xmlhttp.responseText)
});
var myColumns = [];
// create the column model dynamically.
for (var i = 0, len = ajaxReader.meta.fields.length; i < len; i++) {
var field = ajaxReader.meta.fields[i];
if(field.name == 'company') {
var this_column = {};
this_column['id'] = 'company';
this_column['header'] = 'Company';
this_column['width'] = 60;
this_column['sortable'] = true;
this_column['dataIndex'] = 'company';
this_column['hideable'] = false;
this_column['summaryType'] = 'max';
myColumns.push(this_column);
} else if(field.name == 'price') {
var this_column = {};
this_column['id'] = 'price';
this_column['header'] = 'Price';
this_column['width'] = 20;
this_column['sortable'] = true;
this_column['dataIndex'] = 'price';
this_column['renderer'] = Ext.util.Format.usMoney;
this_column['summaryType'] = 'average';
myColumns.push(this_column);
} else if (field.name == 'change') {
// Change
var this_column = {};
this_column['id'] = 'change';
this_column['header'] = 'Change';
this_column['width'] = 20;
this_column['sortable'] = true;
this_column['renderer'] = Ext.util.Format.usMoney;
this_column['dataIndex'] = 'change';
this_column['summaryType'] = 'max';
myColumns.push(this_column);
} else if (field.name == 'industry') {
// Industry
var this_column = {};
this_column['id'] = 'industry';
this_column['header'] = 'Industry';
this_column['width'] = 20;
this_column['sortable'] = true;
this_column['dataIndex'] = 'industry';
myColumns.push(this_column);
} else if (field.name == 'lastChange') {
// Last Updated
var this_column = {};
this_column['id'] = 'lastChange';
this_column['header'] = 'Last Change';
this_column['width'] = 20;
this_column['sortable'] = true;
this_column['dataIndex'] = 'lastChange';
this_column['summaryType'] = 'max';
myColumns.push(this_column);
}
}
var grid2 = new Ext.grid.GridPanel({
store: ajaxStore,
stripeRows: true,
height: 350,
width: 600,
stateful: true,
stateId: 'grid2',
plugins: new Ext.ux.grid.GroupSummary(),
title: 'Stateful + Dynamic Grid Panel with Grouping and Totals',
view: new Ext.grid.GroupingView({
forceFit:true,
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
}),
fbar : ['->', {
text:'Clear Grouping',
iconCls: 'icon-clear-group',
handler : function(){
ajaxStore.clearGrouping();
grid2.fireEvent('groupchange', this);
}
}],
cm: new Ext.grid.ColumnModel({
defaults: {
width: 120,
sortable: true
},
columns: myColumns
})
});
grid2.render('grid-example2');
} else {
// there was an error
// console.error('there was an error getting data from the server');
}
});
The “metaData” in the response below allows the JsonReader to configure itself.
response1.do
{
"metaData" : {
totalProperty : 'totalCount',
root : 'records',
successProperty : "success",
fields : [
{name: 'company', type : 'string'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
{name: 'industry', type : 'string'}
]
},
"success": true,
"totalCount" : "30",
"records" : [
{company: '3m Co' ,price: 71.72,change: 0.02,pctChange: 0.03,lastChange: '4/2 12:00am', industry: 'Manufacturing'},
{company: 'Alcoa Inc' ,price: 29.01,change: 0.42,pctChange: 1.47,lastChange: '4/1 12:00am', industry: 'Manufacturing'},
{company: 'Altria Group Inc' ,price: 83.81,change: 0.28,pctChange: 0.34,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
{company: 'American Express Company' ,price: 52.55,change: 0.01,pctChange: 0.02,lastChange: '4/8 12:00am', industry: 'Finance'},
{company: 'American International Group, Inc.' ,price: 64.13,change: 0.31,pctChange: 0.49,lastChange: '4/1 12:00am', industry: 'Services'},
{company: 'AT&T Inc.' ,price: 31.61,change: -0.48,pctChange: -1.54,lastChange: '4/8 12:00am', industry: 'Services'},
{company: 'Boeing Co.' ,price: 75.43,change: 0.53,pctChange: 0.71,lastChange: '4/8 12:00am', industry: 'Manufacturing'},
{company: 'Caterpillar Inc.' ,price: 67.27,change: 0.92,pctChange: 1.39,lastChange: '4/1 12:00am', industry: 'Services'},
{company: 'Citigroup, Inc.' ,price: 49.37,change: 0.02,pctChange: 0.04,lastChange: '4/4 12:00am', industry: 'Finance'},
{company: 'E.I. du Pont de Nemours and Company' ,price: 40.48,change: 0.51,pctChange: 1.28,lastChange: '4/1 12:00am', industry: 'Manufacturing'},
{company: 'Exxon Mobil Corp' ,price: 68.1,change: -0.43,pctChange: -0.64,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
{company: 'General Electric Company' ,price: 34.14,change: -0.08,pctChange: -0.23,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
{company: 'General Motors Corporation' ,price: 30.27,change: 1.09,pctChange: 3.74,lastChange: '4/3 12:00am', industry: 'Automotive'},
{company: 'Hewlett-Packard Co.' ,price: 36.53,change: -0.03,pctChange: -0.08,lastChange: '4/3 12:00am', industry: 'Computer'},
{company: 'Honeywell Intl Inc' ,price: 38.77,change: 0.05,pctChange: 0.13,lastChange: '4/3 12:00am', industry: 'Manufacturing'},
{company: 'Intel Corporation' ,price: 19.88,change: 0.31,pctChange: 1.58,lastChange: '4/2 12:00am', industry: 'Computer'},
{company: 'International Business Machines' ,price: 81.41,change: 0.44,pctChange: 0.54,lastChange: '4/1 12:00am', industry: 'Computer'},
{company: 'Johnson & Johnson' ,price: 64.72,change: 0.06,pctChange: 0.09,lastChange: '4/2 12:00am', industry: 'Medical'},
{company: 'JP Morgan & Chase & Co' ,price: 45.73,change: 0.07,pctChange: 0.15,lastChange: '4/2 12:00am', industry: 'Finance'},
{company: 'McDonald\'s Corporation' ,price: 36.76,change: 0.86,pctChange: 2.40,lastChange: '4/2 12:00am', industry: 'Food'},
{company: 'Merck & Co., Inc.' ,price: 40.96,change: 0.41,pctChange: 1.01,lastChange: '4/2 12:00am', industry: 'Medical'},
{company: 'Microsoft Corporation' ,price: 25.84,change: 0.14,pctChange: 0.54,lastChange: '4/2 12:00am', industry: 'Computer'},
{company: 'Pfizer Inc' ,price: 27.96,change: 0.4,pctChange: 1.45,lastChange: '4/8 12:00am', industry: 'Services'},
{company: 'The Coca-Cola Company' ,price: 45.07,change: 0.26,pctChange: 0.58,lastChange: '4/1 12:00am', industry: 'Food'},
{company: 'The Home Depot, Inc.' ,price: 34.64,change: 0.35,pctChange: 1.02,lastChange: '4/8 12:00am', industry: 'Retail'},
{company: 'The Procter & Gamble Company' ,price: 61.91,change: 0.01,pctChange: 0.02,lastChange: '4/1 12:00am', industry: 'Manufacturing'},
{company: 'United Technologies Corporation' ,price: 63.26,change: 0.55,pctChange: 0.88,lastChange: '4/1 12:00am', industry: 'Computer'},
{company: 'Verizon Communications' ,price: 35.57,change: 0.39,pctChange: 1.11,lastChange: '4/3 12:00am', industry: 'Services'},
{company: 'Wal-Mart Stores, Inc.' ,price: 45.45,change: 0.73,pctChange: 1.63,lastChange: '4/3 12:00am', industry: 'Retail'},
{company: 'Walt Disney Company (The) (Holding Company)',price: 29.89,change: 0.24,pctChange: 0.81,lastChange: '4/1 12:00am', industry: 'Services'}
]
}
Test the page
The page will NOT work if you simply save the files to a local directory and point your browser there. The pages must be served by a HTTP Server. Setting up a server is beyond the scope of this page.