ExtJS Dynamic Grid Columns

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.


  • Html Editor
  • HTTP Server to serve the pages from


Create the following html page:


  1. Make an Ajax request using the Standard XMLHttpRequest browser object.
  2. Read the meta-data from the response
  3. Run thru a series of if-else conditions to create and insert columns into the dynamic column model
  4. Feed the GridPanel with the store and the column model.

The following html file sets up the styles and imports the core JavaScript libraries.


    <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;
	border: 1px solid #6593cf;
	border: 1px solid #b3bcc0;
	border: 1px solid #cbc7b8;
	left: 0;
	position: relative;
	top: 0;
#editor-grid .x-grid-col-2{
.x-grid3-td-topic b {
    font-family:tahoma, verdana;
.x-grid3-td-topic b i {
    font-style: normal;
.x-grid3-td-topic .x-grid3-cell-inner {
.x-grid3-td-topic a {
    color: #385F95;
.x-grid3-td-topic a:hover {
.details .x-btn-text {
    background-image: url(details.gif);
.x-resizable-pinned .x-resizable-handle-south{
    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);

    <!-- 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"
<script type="text/javascript"

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

    <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>



    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

	var prefs = {};
    if(xmlhttp.status == 200) {
	    var ajaxReader = new Ext.data.JsonReader();
		var ajaxStore = new Ext.data.GroupingStore({
			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';                    
			} 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';
			} 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';
			} 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';
			} 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';
		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({
			    groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
			fbar  : ['->', {
			    text:'Clear Grouping',
			    iconCls: 'icon-clear-group',
			    handler : function(){
			        grid2.fireEvent('groupchange', this);
			cm: new Ext.grid.ColumnModel({
				defaults: {
					width: 120,
					sortable: true
				columns: myColumns
    } 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.


"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.


2 Responses to “ExtJS Dynamic Grid Columns”

  1. February 7, 2012 at 4:17 pm

    very usefull, thanks!!

  2. February 12, 2014 at 7:29 am

    Hi there,

    This post is absolutely helpful. but i have a question. I wanted to change the GroupingStore’s data to url. but it is throwing that ajaxReader.meta.fields is undefined error.

    Any suggestion would be great.

    Thanks in advance.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 77 other followers

March 2011
« Feb   Apr »

Blog Stats

  • 847,163 hits

%d bloggers like this: