Blog Archive

ExtJs 4 Grid Grouping and Summary example - Expand and Collapse all

GroupingSummary feature with Hide/Show Summary, Enable/Disable feature, Expand All/Collapse All buttons

Ext.grid.feature.GroupingSummary feature in ExtJs 4 displays a Group heading based on a given group field and in addition to that a summary line for every break in the group heading. For just grouping use the Grouping feature (Ext.grid.feature.Grouping) and for just summary use the Summary feature (Ext.grid.feature.Summary).


To do the grouping you have to specify the groupField property in your Grid store. At this time there is no multi-level grouping feature available, may be it will be added in later releases. In this example we have created a new field by combining two fields Continent and Region so we can do a break for each Continent and Region combination. You can manipulate the group heading using the groupHeaderTpl config. The name object gives you the value of the groupField. There is also the rows object that gives you how many rows are there for that group header.

For the summary row there you have two configs summaryType and summaryRenderer. With summaryType you specify what type of summary you want to display for that column. Is it just a count or average or anything else. There are several built in summary types such as count, sum, min, max and average. You can also define a custom function to define a summary value. The function is called with an array of records. Just like renderer for each column the summaryRenderer is for just the summary row. The summaryRenderer is called with the following parameters
  • value {Object} - The calculated value.
  • summaryData {Object} - Contains all raw summary values for the row.
  • field {String} - The name of the field we are calculating

ExtJs 4 Grid GroupingSummary feature example
ExtJs 4 Grid GroupingSummary feature example
ExtJs 4 Grid GroupingSummary feature example

Application HTML file - index.html

<html>
<head>
    <title>ExtJs 4 Grid Group Summary Feature Example </title>

    <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css">
    <link rel="stylesheet" type="text/css" href="extjs/ux/css/CheckHeader.css">
    <style type="text/css" media="screen">
        .x-grid-row-summary .x-grid-cell-inner {
            font-weight: bold;
            font-size: 12px;
        }
    </style>
    <script type="text/javascript" src="extjs/ext-all-debug.js"></script>
    <script type="text/javascript" src="app.js"></script>

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

Application Javascript file - app.js

Ext.Loader.setConfig({ 
    enabled: true 
    });

Ext.require([
             'Ext.data.*',
             'Ext.grid.*',
         ]);

Ext.application({
   
    name: 'MyApp',
    appFolder: 'app',
    controllers: [
                  'Countries'
              ],

    launch: function() {
        Ext.create('Ext.container.Viewport', {
            items: [
                {
                    xtype: 'countryList',
                }
            ]
        });
    }
});

Country data model - Country.js

Ext.define('MyApp.model.Country', {
    extend: 'Ext.data.Model',
    fields: [
         'code',
         'name',
         'continent',
         'region',
         'lifeExpectancy',
         'gnp',
         {
             name: 'myGroup',
             mapping: 'continent',
             convert: function(v, record) {
                     return v + ': ' + record.data.region;
             }
        }]
});

Country data store - Countries.js

Ext.define('MyApp.store.Countries', {
    extend: 'Ext.data.Store',
    model: 'MyApp.model.Country',
    autoLoad: true,
    groupField: 'myGroup',
   
    proxy: {
        type: 'ajax',
        url: 'CountryServlet',
        reader: {
            type: 'json',
            totalProperty: 'totalCount',
            root: 'countries',
            successProperty: 'success'
        },
     }
});

Country grid view with Summary and Grouping - CountryList.js

Ext.define('MyApp.view.CountryList' ,{
    extend: 'Ext.grid.Panel',
    alias : 'widget.countryList',
    title : 'List of Countries Grouped by Continent and Region',
    store : 'Countries',
    loadMask: true,
    height: 400,
    width: 600,
    margin: '10 0 0 10',
    dockedItems: [{
        xtype: 'toolbar',
        dock: 'bottom',
        items: [
                {
                    id: 'hideShow',
                    xtype : 'button',
                    text: 'Hide Summary',
                    pressed: true,
                    enableToggle: true
                },
                { 
                    xtype: 'tbseparator' 
                },
                {
                    id: 'grouping',
                    xtype : 'button',
                    text: 'Disable Grouping',
                    pressed: true,
                    enableToggle: true
                },
                { 
                    xtype: 'tbseparator' 
                },
                {
                    id: 'collapse',
                    xtype : 'button',
                    text: 'Collapse All',
                    pressed: true,
                    enableToggle: true
                },
        ]
    }],
   
    features: [
        Ext.create('Ext.grid.feature.GroupingSummary', {
            id: 'groupSummary',
            groupHeaderTpl: '{name} ({rows.length} {[values.rows.length > 1 ? "Countries" : "Country"]})'
        })        
    ],

    initComponent: function() {
           
        this.columns = [
            {header: 'Country Code', dataIndex: 'code',  flex: 1},
            {header: 'Name', dataIndex: 'name', flex: 2,
                summaryType: function(records){
                    var myGroupName = records[0].get('myGroup');
                    return myGroupName;
                }
            },
            {header: 'Life Expectancy', dataIndex: 'lifeExpectancy', flex: 1,
                summaryType: 'average',   
                summaryRenderer: Ext.util.Format.numberRenderer('0.00')
            },
            {header: 'GNP', dataIndex: 'gnp', flex: 1,
                summaryType: 'average',
                summaryRenderer: Ext.util.Format.numberRenderer('0.00')
            }
        ];
   
        this.callParent(arguments);
    }

  
});

Application controller - Countries.js

Ext.define('MyApp.controller.Countries', {
            extend : 'Ext.app.Controller',

            //define the stores
            stores : ['Countries'],
            //define the models
            models : ['Country'],
            //define the views
            views : ['CountryList'],
            //define refs
            refs: [{
                ref: 'myCountryList', 
                selector: 'countryList'
            }],
           
            init : function() {
                this.control({
                   
                    'viewport > panel' : {
                        render : this.onPanelRendered
                    },
                    'countryList button[id=hideShow]' : {
                        toggle : this.onSummaryToggle   
                    },
                    'countryList button[id=grouping]' : {
                        toggle : this.onSummaryDisable   
                    },
                    'countryList button[id=collapse]' : {
                        toggle : this.onGroupCollapse   
                    }
                   
                });
            },

            onPanelRendered : function() {
                //just a console log to show when the panel si rendered
                console.log('The panel was rendered');
            },
           
            onSummaryToggle : function(button, pressed) {
                console.log('Sumary toggle button was pressed: ' + pressed);
                var buttonText = pressed ? 'Hide Summary' : 'Show Summary';
                button.setText(buttonText);
                var view = this.getMyCountryList().getView();
                view.getFeature('groupSummary').toggleSummaryRow(pressed);
                view.refresh();
            },
           
            onSummaryDisable : function(button, pressed) {
                console.log('Sumary enable/disable button was pressed: ' + pressed);
                var view = this.getMyCountryList().getView();
                if(pressed){
                    button.setText('Disable Grouping');
                    view.getFeature('groupSummary').enable();
                }
                else {
                    button.setText('Enable Grouping');
                    view.getFeature('groupSummary').disable();
                }
            },
           
            onGroupCollapse : function(button, pressed) {
                console.log('Sumary enable/disable button was pressed: ' + pressed);
                var view = this.getMyCountryList().getView();
                var groupFeature = view.getFeature('groupSummary');
                if(pressed){
                    button.setText('Collapse All');
                    view.getEl().query('.x-grid-group-hd').forEach(function (group) {
                        var groupBody = Ext.fly(group.nextSibling, '_grouping');
                        groupFeature.expand(groupBody);
                    });
                }
                else {
                    button.setText('Expand All');
                    view.getEl().query('.x-grid-group-hd').forEach(function (group) {
                        var groupBody = Ext.fly(group.nextSibling, '_grouping');
                        groupFeature.collapse(groupBody);
                    });
                }
            }
           
    });

ExtJs 4 Grid summary data from Remote Server

You can get data for the summary row from the server using the Store AJAX request. Just pass an array of objects for the summary row in a separate node and specify that in the Ext.grid.feature.GroupingSummary remoteRoot config. Here is an example from the the sencha docs - http://dev.sencha.com/deploy/ext-4.0.0/examples/grid/remote-group-summary-grid.html

In the example above the remoteRoot is set to summaryData. Here is the data coming from the server in the summaryData node
summaryData: [
         {project: 'Ext Grid: Single-level Grouping', description: 13, estimate: 6, rate: 100, due:'07/06/2012', cost: 1234},
         {project: 'Ext Forms: Field Anchoring', description: 14, estimate: 9, rate: 50, due:'06/29/2007', cost: 999},
         {project: 'Ext Grid: Summary Rows', description: 11, estimate: 4, rate: 44, due:'06/29/2011', cost: 789}
    ]