Angular DataGrid - summary

Specifies the properties of the grid summary.

Selector: dxo-summary
Type:

Summary

A summary is a grid feature that provides a synopsis of data contained in the grid. A summary consists of several items. A summary item displays a value that is a product of applying an aggregate function to the data of a specific column.

There are two types of summary in DataGrid: group and total. The group summary is calculated on a group of data, which is segregated during grouping. To specify the items of the group summary, declare an array of objects and assign it to the summary.groupItems field.

The total summary is calculated on all data contained in the grid. To specify the items of the total summary, declare an array of objects and assign it to the summary.totalItems field.

Group Summaries Demo Total Summaries Demo

calculateCustomSummary

Specifies a custom aggregate function. This function is called for summary items whose summaryType is "custom".

Type:

Function

Function parameters:
options:

Object

Summary information.

Object structure:
Name Type Description
value any

A column value used to calculate the summary. If you need an entire data object in this field, do not specify the summary item's column property. To display the summary in this case, use the showInColumn property instead.

totalValue any

The resulting summary item's value.

summaryProcess

String

Indicates the stage of the summary item calculation; equals "start", "calculate" or "finalize".

name

String

The summary item's name.

groupIndex

Number

A zero-based group level. Available only when calculating group summary items.

component

DataGrid

The UI component's instance.

This is a single function for all custom summary items. Specify a name for each item to identify it in the function.

A summary value calculation is conducted in three stages: start - the totalValue is initialized; calculate - the totalValue is modified; finalize - the totalValue is adjusted. To identify the current stage, check the value of the summaryProcess field that belongs to the function's parameter:

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        // ...
        summary: {
            totalItems: [
                { name: "customSummary1", summaryType: "custom" },
                { name: "customSummary2", summaryType: "custom" }
            ],
            calculateCustomSummary: function(options) {
                // Calculating "customSummary1"
                if(options.name == "customSummary1") {
                    switch(options.summaryProcess) {
                        case "start":
                            // Initializing "totalValue" here
                            break;
                        case "calculate":
                            // Modifying "totalValue" here
                            break;
                        case "finalize":
                            // Assigning the final value to "totalValue" here
                            break;
                    }
                }

                // Calculating "customSummary2"
                if(options.name == "customSummary2") {
                    // ...
                    // Same "switch" statement here
                }
            }
        }
    });
});
Angular
app.component.html
app.component.ts
app.module.ts
<dx-data-grid ... >
    <dxo-summary [calculateCustomSummary]="calculateSummary">
        <dxi-total-item
            name="сustomSummary1"
            summaryType="custom">
        </dxi-total-item>
        <dxi-total-item
            name="сustomSummary2"
            summaryType="custom">
        </dxi-total-item>
    </dxo-summary>
</dx-data-grid>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    calculateSummary(options) {
        // Calculating "customSummary1"
        if(options.name == "customSummary1") {
            switch(options.summaryProcess) {
                case "start":
                    // Initializing "totalValue" here
                    break;
                case "calculate":
                    // Modifying "totalValue" here
                    break;
                case "finalize":
                    // Assigning the final value to "totalValue" here
                    break;
            }
        }

        // Calculating "customSummary2"
        if(options.name == "customSummary2") {
            // ...
            // Same "switch" statement here
        }
    };
}
import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { AppComponent } from './app.component'; 
import { DxDataGridModule } from 'devextreme-angular'; 

@NgModule({ 
    declarations: [ 
        AppComponent 
    ], 
    imports: [ 
        BrowserModule, 
        DxDataGridModule 
    ], 
    providers: [ ], 
    bootstrap: [AppComponent] 
}) 

export class AppModule { } 
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxSummary :calculate-custom-summary="calculateCustomSummary">
            <DxTotalItem
                name="сustomSummary1"
                summary-type="custom"
            />
            <DxTotalItem
                name="сustomSummary2"
                summary-type="custom"
            />
        </DxSummary>
    </DxDataGrid>
</template>
<script>
import { DxDataGrid, DxSummary, DxTotalItem } from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxSummary, 
        DxTotalItem
    },
    methods: {
        calculateCustomSummary(options) {
            // Calculating "customSummary1"
            if(options.name == "customSummary1") {
                switch(options.summaryProcess) {
                    case "start":
                        // Initializing "totalValue" here
                        break;
                    case "calculate":
                        // Modifying "totalValue" here
                        break;
                    case "finalize":
                        // Assigning the final value to "totalValue" here
                        break;
                }
            }

            // Calculating "customSummary2"
            if(options.name == "customSummary2") {
                // ...
                // Same "switch" statement here
            }
        },
    },
}
</script>
React
App.js
import React from 'react';
import DataGrid, { Column, TotalItem } from 'devextreme-react/data-grid';

const calculateCustomSummary = (options) => {
    // Calculating "customSummary1"
    if(options.name == "customSummary1") {
        switch(options.summaryProcess) {
            case "start":
                // Initializing "totalValue" here
                break;
            case "calculate":
                // Modifying "totalValue" here
                break;
            case "finalize":
                // Assigning the final value to "totalValue" here
                break;
        }
    }

    // Calculating "customSummary2"
    if(options.name == "customSummary2") {
        // ...
        // Same "switch" statement here
    }
}

function App() {
    return (
        <DataGrid ... >
            <Summary calculateCustomSummary={calculateCustomSummary}>
                <TotalItem
                    name="customSummary1"
                    summaryType="custom"
                />
                <TotalItem
                    name="customSummary2"
                    summaryType="custom"
                />
            </Summary>
        </DataGrid>
    );
}

export default App;

You can use the value field to retrieve the column value. If you do not specify a column for which to calculate the summary, the value field contains an entire data object. However, this object misses values from unbound columns calculated in the calculateCellValue function. If you need these values for your custom summary, call the calculateCellValue function from inside calculateCustomSummary, as shown below. In this example, the calculateArea (calculateCellValue) function creates an unbound column 'Area'. The same function is called from the calculateAreaSummary (calculateCustomSummary) function to compute the sum of areas for selected rows.

jQuery
JavaScript
const calculateArea = (rowData) => {
    return rowData.width * rowData.height;
}

const calculateAreaSummary = (options) => {
    if (options.name === "AreaSummary") {
        if (options.summaryProcess === "start") {
            options.totalValue = 0;
        }
        if (options.summaryProcess === "calculate") {
            if (options.component.isRowSelected(options.value.ID)) {
                options.totalValue += calculateArea(options.value);                      
            }
        }
    }
}  

$(function(){    
    $("#gridContainer").dxDataGrid({
        // ...
        selectedRowKeys: [12, 13],
        columns: [
            "width", "height",
            {
                dataField: "Area",
                calculateCellValue: calculateArea
            }
        ],
        summary: {
            totalItems: [{
                name: "AreaSummary",
                summaryType: "custom"
                showInColumn: "Area",
                displayFormat: "Total Area: {0}",
            }],
            calculateCustomSummary: calculateAreaSummary
        }
    });
});
Angular
app.component.ts
app.component.html
app.module.ts
import { Component } from '@angular/core';
// ...
export class AppComponent {
    selectedRows: number[];

    constructor() {
        // ...
        this.selectedRows = [12, 13];
        this.calculateAreaSummary = this.calculateAreaSummary.bind(this);
    }

    calculateArea(rowData) {
        return rowData.width * rowData.height;
    }

    calculateAreaSummary(options) {
        if (options.name === "AreaSummary") {
            if (options.summaryProcess === "start") {
                options.totalValue = 0;
            }
            if (options.summaryProcess === "calculate") {
                if (options.component.isRowSelected(options.value.ID)) {
                    options.totalValue += calculateArea(options.value);
                }
            }
        }
    }
}
<dx-data-grid ... 
    [selectedRowKeys]="selectedRows">
    <dxi-column dataField="width"></dxi-column>
    <dxi-column dataField="height"></dxi-column>
    <dxi-column
        dataField="Area"
        [calculateCellValue]="calculateArea">
    </dxi-column>
    <dxo-summary [calculateCustomSummary]="calculateAreaSummary">
        <dxi-total-item
            name="AreaSummary"
            summaryType="custom"
            showInColumn="Area"
            displayFormat="Total Area: {0}">
        </dxi-total-item>
    </dxo-summary>
</dx-data-grid>
import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { AppComponent } from './app.component'; 
import { DxDataGridModule } from 'devextreme-angular'; 

@NgModule({ 
    declarations: [ 
        AppComponent 
    ], 
    imports: [ 
        BrowserModule, 
        DxDataGridModule 
    ], 
    providers: [ ], 
    bootstrap: [AppComponent] 
}) 

export class AppModule { } 
Vue
App.vue
<template>
    <DxDataGrid ... 
        :selected-row-keys="selectedRowKeys">
        <DxColumn data-field="width" />
        <DxColumn data-field="height" />
        <DxColumn 
            data-field="Area" 
            :calculate-cell-value="calculateArea" 
        />
        <DxSummary :calculate-custom-summary="calculateAreaSummary">
            <DxTotalItem
                name="AreaSummary"
                summary-type="custom"
                show-in-column="Area"
                display-format="Total Area: {0}"
            />
        </DxSummary>
    </DxDataGrid>
</template>
<script>
import { DxDataGrid, DxColumn, DxSummary, DxTotalItem } from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn,
        DxSummary, 
        DxTotalItem
    },
    data() {
        return {
            // ...
            selectedRowKeys: [12, 13]
        };
    },
    methods: {
        calculateArea(rowData) {
            return rowData.width * rowData.height;
        },
        calculateAreaSummary(options) {
            if (options.name === "AreaSummary") {
                if (options.summaryProcess === "start") {
                    options.totalValue = 0;
                }
                if (options.summaryProcess === "calculate") {
                    if (options.component.isRowSelected(options.value.ID)) {
                        options.totalValue += this.calculateArea(options.value);
                    }
                }
            }
        },
    },
}
</script>
React
App.js
import React from 'react';
import DataGrid, { Column, Summary, TotalItem } from 'devextreme-react/data-grid';

const calculateArea = (rowData) => {
    return rowData.width * rowData.height;
}

const calculateAreaSummary = (options) => {
    if (options.name === "AreaSummary") {
        if (options.summaryProcess === "start") {
            options.totalValue = 0;
        }
        if (options.summaryProcess === "calculate") {
            if (options.component.isRowSelected(options.value.ID)) {
                options.totalValue += calculateArea(options.value);
            }
        }
    }
}

function App() {
    // ...
    const selectedRowKeys = [12, 13];

    return (
        <DataGrid ... 
            selectedRowKeys={selectedRowKeys}>
            <Column dataField="width" />
            <Column dataField="height" />
            <Column dataField="Area" calculateCellValue={calculateArea} />
            <Summary calculateCustomSummary={calculateAreaSummary}>
                <TotalItem
                    name="AreaSummary"
                    summaryType="custom"
                    showInColumn="Area"
                    displayFormat="Total Area: {0}"
                />
            </Summary>
        </DataGrid>
    );
}

export default App;

View Demo

See Also

groupItems[]

Specifies items of the group summary.

Selector: dxi-group-item
Default Value: undefined

The group summary provides a synopsis of a group of data. Groups of data are formed in the process of grouping. The group summary contains several items. Each item displays a value that is a product of applying an aggregate function to a group of data.

To specify the items of the group summary, declare an array of objects, each of which contains at least two fields: column and summaryType. The column field specifies the identifier of the column that provides data for an aggregate function. The summaryType specifies the aggregate function to be applied. The following code snippet shows how to declare two summary items.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        summary: {
            groupItems: [{
                column: "Age",
                summaryType: "avg"
            }, {
                column: "LastName",
                summaryType: "count"
            }]
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-summary>
        <dxi-group-item
            column="Age"
            summaryType="avg">
        </dxi-group-item>
        <dxi-group-item
            column="LastName"
            summaryType="count">
        </dxi-group-item>
    </dxo-summary>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxSummary>
            <DxGroupItem
                column="Age"
                summary-type="avg"
            />
            <DxGroupItem
                column="LastName"
                summary-type="count"
            />
        </DxSummary>
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxDataGrid, {
    DxSummary,
    DxGroupItem
} from 'devextreme-vue/data-grid';

export default {
    components: {              
        DxDataGrid,
        DxSummary,
        DxGroupItem
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    Summary,
    GroupItem
} from 'devextreme-react/data-grid';

export default function App() {
    return (
        <DataGrid ... >
            <Summary>
                <GroupItem
                    column="Age"
                    summaryType="avg"
                />
                <GroupItem
                    column="LastName"
                    summaryType="count"
                />
            </Summary>
        </DataGrid>
    );
}

A group summary item may be located either in the group row or the group footer. By default, the group row holds all summary items. To locate a summary item in the group footer, set the showInGroupFooter property of this item to true.

View Demo

See Also

recalculateWhileEditing

Specifies whether to recalculate summaries while a user edits data.

Type:

Boolean

Default Value: false

skipEmptyValues

Specifies whether to skip empty strings, null and undefined values when calculating a summary. Does not apply when you use a remote data source.

Type:

Boolean

Default Value: true

Specified in the summary object, this property affects all summaries in the grid. In addition, the same property can be specified for an individual summary. It will override the global setting.

NOTE

Summaries of the count type do not skip empty values regardless of the skipEmptyValues property. However, you can implement a custom summary that skips empty values, as follows:

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        summary: {
            totalItems: [{
                // ...
                name: "customSummary1",
                summaryType: "custom"
            }],
            calculateCustomSummary: function (options) {
                if (options.name == "customSummary1") {
                    if (options.summaryProcess == "start") {
                        options.totalValue = 0;
                    }
                    if (options.summaryProcess == "calculate") {
                        if (e.value) {
                            options.totalValue++;
                        }
                    }
                }
            }
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-summary [calculateCustomSummary]="calculateSummary">
        <dxi-total-item
            summaryType="custom"
            name="customSummary1">
        </dxi-total-item>
    </dxo-summary>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    calculateSummary (options) {
        if (options.name == "customSummary1") {
            if (options.summaryProcess == "start") {
                options.totalValue = 0;
            }
            if (options.summaryProcess == "calculate") {
                if (e.value) {
                    options.totalValue++;
                }
            }
        }
    };
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxSummary
            :calculate-custom-summary="calculateSummary">
            <DxTotalItem
                summary-type="custom"
                name="customSummary1"
            />
        </DxSummary>
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxDataGrid, {
    DxSummary,
    DxTotalItem
} from 'devextreme-vue/data-grid';

export default {
    components: {              
        DxDataGrid,
        DxSummary,
        DxTotalItem
    },
    // ...
    methods: {
        calculateSummary (options) {
            if (options.name == "customSummary1") {
                if (options.summaryProcess == "start") {
                    options.totalValue = 0;
                }
                if (options.summaryProcess == "calculate") {
                    if (e.value) {
                        options.totalValue++;
                    }
                }
            }
        }
    }
}
</script>
React
App.js
import React, { useCallback } from 'react';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    Summary,
    TotalItem
} from 'devextreme-react/data-grid';

export default function App() {
    const calculateSummary = useCallback((options) => {
        if (options.name == "customSummary1") {
            if (options.summaryProcess == "start") {
                options.totalValue = 0;
            }
            if (options.summaryProcess == "calculate") {
                if (e.value) {
                    options.totalValue++;
                }
            }
        }
    }, []);

    return (
        <DataGrid ... >
            <Summary
                сalculateCustomSummary={calculateSummary}>
                <TotalItem
                    summarType="custom"
                    name="customSummary1"
                />
            </Summary>
        </DataGrid>
    );
}

texts

Contains properties that specify text patterns for summary items.

Selector: dxo-texts
Type:

SummaryTexts

Depending on their type, summary items use one of predefined text patterns specified in the summary.texts object. For example, summary items of the "avg" type use the pattern specified by the avg field of the texts object.

By default, a summary item is located in the column that provides data for it. This column is called the "parent column". However, a summary item may be located in any other column or in a group row. To specify text patterns for such summary items, use properties with the OtherColumn addition in their name. For example, summary items of the "avg" type located outside their parent column use the pattern specified by the avgOtherColumn field of the texts object.

When implementing a pattern, you can access the summary item value with applied format using position marker 0. If the summary item is placed outside its parent column, you can also access the caption of the parent column using position marker 1. Place each of these position markers within curly brackets.

totalItems[]

Specifies items of the total summary.

Selector: dxi-total-item
Default Value: undefined

The total summary, which is located in the grid footer, provides a synopsis of all data contained in the grid. It contains several summary items. Each item displays a value that is a product of applying an aggregate function to the data of a specific column.

To specify the items of the total summary, declare an array of objects, each of which contains at least two fields: column and summaryType. The column field specifies the identifier of the column that provides data for an aggregate function. The summaryType specifies the aggregate function to be applied. The following code snippet shows how to declare two summary items.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        summary: {
            totalItems: [{
                column: "Age",
                summaryType: "avg"
            }, {
                column: "LastName",
                summaryType: "count"
            }]
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-summary>
        <dxi-total-item
            column="Age"
            summaryType="avg">
        </dxi-total-item>
        <dxi-total-item
            column="LastName"
            summaryType="count">
        </dxi-total-item>
    </dxo-summary>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxSummary>
            <DxTotalItem
                column="Age"
                summary-type="avg"
            />
            <DxTotalItem
                column="LastName"
                summary-type="count"
            />
        </DxSummary>
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxDataGrid, {
    DxSummary,
    DxTotalItem
} from 'devextreme-vue/data-grid';

export default {
    components: {              
        DxDataGrid,
        DxSummary,
        DxTotalItem
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    Summary,
    TotalItem
} from 'devextreme-react/data-grid';

export default function App() {
    return (
        <DataGrid ... >
            <Summary>
                <TotalItem
                    column="Age"
                    summaryType="avg"
                />
                <TotalItem
                    column="LastName"
                    summaryType="count"
                />
            </Summary>
        </DataGrid>
    );
}

By default, a summary item is placed in the column that provides data for it. If you need to place it in another column, assign the identifier of this column to the showInColumn property.

View Demo

See Also