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

13 comments :

  1. can u help with charting this grouped data in pie chart; life expectancy for groups

    thanks

    ReplyDelete
  2. Great example !!! MILLION THANKS

    ReplyDelete
  3. Thanks a lot fot the example. But I have Issue with the "Collapse All", this functionality is not working for me.
    "group.nextSibling" is failing as I am getting the "group" as "DIV". Following is the error "Uncaught TypeError: Cannot read property 'isCollapsed' of undefined "

    Can you please let me know what might be the issue.

    Thanks in Advance

    ReplyDelete
  4. Thank you for the sample. I found a bug here - say if you add an extra column in as xtype: 'checkcolumn', and have the dataIndex set properly, when store loads, it was loaded perfect, checked or unchecked.

    Here comes the issue: if you collapse the top group, the rest of the groups' checkcolumn would no longer work. By checking or unchecking other group's checkcolumn boxes, you wouldn't see any reflection on your action. BUT as the group you just collapsed, the checkcolumn boxes were actually responded to your action you performed on another group.

    any clues on solving this?

    ReplyDelete
  5. compliments a great job, one question, do you know how to operate groupingView / groupSummary if the values ​​that should be added together have the comma as the decimal separator?
    thanks a lot in advance. Giorgio Paganelli (paganellig@tiscali.it)

    ReplyDelete
  6. can we know the structure of json data used by the store here

    ReplyDelete
  7. Hello there..

    Thanks for the nice article. Well, now I am using grouping feature in grid panel but can we apply grouping on those rows whose having more than >1 records and with startCollapsed =true else false...???? Currently I am getting grouping in each row but i need to apply conditional wise.. hope you understand what i have meant to say.

    thanks

    ReplyDelete
  8. Can you please upload this code to GIThub?

    ReplyDelete
  9. The summarizing an article is now on finger tips because we have some expertise who help us in various ways.

    ReplyDelete