Grouping with Aggregation
Overview
Section titled “Overview”The Grouping with Aggregation feature allows you to organize your data into hierarchical groups and display custom aggregated values for each group. This is particularly useful for displaying summary statistics, totals, averages, or custom calculations for grouped data.
Key Features
Section titled “Key Features”- Hierarchical Grouping: Group data by multiple columns in a tree-like structure
- Custom Aggregations: Define custom aggregation functions for different data types
- Visual Indicators: Expandable/collapsible groups with aggregation values displayed
- Flexible Templates: Customize how group headers and aggregations are displayed
Basic Usage
Section titled “Basic Usage”Source code
import { defineCustomElements } from '@revolist/revogrid/loader';import { currentTheme } from '../composables/useRandomData';import { createGroupingData, columns, grouping } from './groupingData';
defineCustomElements();
export function load(parentSelector: string) { const grid = document.createElement('revo-grid'); const { isDark } = currentTheme();
// Generate realistic data using faker.js grid.source = createGroupingData(50); grid.columns = columns; grid.grouping = grouping;
// Grouping is a built-in feature, no plugin needed grid.theme = isDark() ? 'darkCompact' : 'compact'; grid.hideAttribution = true;
document.querySelector(parentSelector)?.appendChild(grid);}
<template> <RevoGrid class="rounded-lg overflow-hidden cell-border" :columns="columns" :source="source" :grouping="grouping" :theme="isDark ? 'darkMaterial' : 'material'" hide-attribution /></template>
<script setup lang="ts">import RevoGrid from '@revolist/vue3-datagrid';import { ref } from 'vue';import { currentThemeVue } from '../composables/useRandomData';import { createGroupingData, columns, grouping } from './groupingData';
const { isDark } = currentThemeVue();
// Generate realistic data using faker.jsconst source = ref(createGroupingData(50));
// Grouping is a built-in feature, no plugin needed</script>
import React, { useMemo } from 'react';import { RevoGrid } from '@revolist/react-datagrid';import { currentTheme } from '../composables/useRandomData';import { createGroupingData, columns, grouping } from './groupingData';
const { isDark } = currentTheme();
function Grouping() { // Generate realistic data using faker.js const source = useMemo(() => createGroupingData(50), []);
return ( <RevoGrid source={source} columns={columns} grouping={grouping} theme={isDark() ? 'darkCompact' : 'compact'} hideAttribution /> );}
export default Grouping;
import { Component, OnInit } from '@angular/core';import { RevoGrid } from '@revolist/angular-datagrid';import { currentTheme } from '../composables/useRandomData';import { createGroupingData, columns, grouping } from './groupingData';
@Component({ selector: 'grouping-grid', standalone: true, imports: [RevoGrid], template: ` <revo-grid [source]="source" [columns]="columns" [grouping]="grouping" [theme]="theme" [hideAttribution]="true" style="height: 400px;" ></revo-grid> `})export class GroupingGridComponent implements OnInit { // Generate realistic data using faker.js source = createGroupingData(50); columns = columns; grouping = grouping; theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
ngOnInit() { // Any additional initialization logic }}
Implementation
Section titled “Implementation”1. Import Required Components
Section titled “1. Import Required Components”import { groupingAggregation } from '@revolist/revogrid-pro';
2. Define Aggregation Functions
Section titled “2. Define Aggregation Functions”Create custom aggregation functions for different columns. Important: Aggregation functions receive an array of complete data objects, not just the column values. You need to extract the specific property you want to aggregate:
const aggregations = { price: (values: any[]) => { const prices = values.map(item => item.price); const sum = prices.reduce((acc, val) => acc + val, 0); const avg = sum / prices.length; return `Avg: $${avg.toFixed(2)}`; }, quantity: (values: any[]) => { const quantities = values.map(item => item.quantity); const total = quantities.reduce((acc, val) => acc + val, 0); return `Total: ${total}`; }, product: (values: any[]) => { return `${values.length} products`; }};
3. Create Group Template
Section titled “3. Create Group Template”Use the groupingAggregation
function to create a template that displays aggregations:
const groupTemplate = (h: any, props: any) => { return groupingAggregation(h, props, aggregations);};
4. Configure Columns
Section titled “4. Configure Columns”Apply the group template to columns that will be used for grouping:
const columns = [ { name: '🆔 ID', prop: 'id', size: 60 }, { name: '📂 Category', prop: 'category', size: 120, template: groupTemplate }, { name: '📁 Subcategory', prop: 'subcategory', size: 120, template: groupTemplate }, { name: '📦 Product', prop: 'product', size: 150 }, { name: '💰 Price', prop: 'price', size: 100 }, { name: '📊 Quantity', prop: 'quantity', size: 100 }, { name: '📅 Order Date', prop: 'orderDate', size: 120 }, { name: '🚚 Delivery Date', prop: 'deliveryDate', size: 120 }, { name: '👤 Customer', prop: 'customer', size: 150 }, { name: '🌍 Region', prop: 'region', size: 100 }, { name: '📋 Status', prop: 'status', size: 100 },];
5. Set Up Grouping Configuration
Section titled “5. Set Up Grouping Configuration”Define which columns should be used for grouping:
const grouping = { props: ['orderDate', 'category', 'subcategory']};
6. Initialize the Grid
Section titled “6. Initialize the Grid”const grid = document.createElement('revo-grid');grid.source = yourData;grid.columns = columns;grid.grouping = grouping;// Grouping is a built-in feature, no plugin needed
Aggregation Function Examples
Section titled “Aggregation Function Examples”Numeric Aggregations
Section titled “Numeric Aggregations”// Averageprice: (values: any[]) => { const prices = values.map(item => item.price); const avg = prices.reduce((acc, val) => acc + val, 0) / prices.length; return `Avg: $${avg.toFixed(2)}`;}
// Sumquantity: (values: any[]) => { const quantities = values.map(item => item.quantity); const total = quantities.reduce((acc, val) => acc + val, 0); return `Total: ${total}`;}
// Min/Maxprice: (values: any[]) => { const prices = values.map(item => item.price); const min = Math.min(...prices); const max = Math.max(...prices); return `Range: $${min} - $${max}`;}
String Aggregations
Section titled “String Aggregations”// Countproduct: (values: any[]) => { return `${values.length} products`;}
// Concatenationnames: (values: any[]) => { const names = values.map(item => item.name); return names.join(', ');}
// Unique countcategories: (values: any[]) => { const categories = values.map(item => item.category); const unique = new Set(categories); return `${unique.size} unique categories`;}
Date Aggregations
Section titled “Date Aggregations”// Date rangeorderDate: (values: any[]) => { const dates = values.map(item => new Date(item.orderDate)); const sorted = dates.sort((a, b) => a.getTime() - b.getTime()); const earliest = sorted[0].toLocaleDateString(); const latest = sorted[sorted.length - 1].toLocaleDateString(); return `${earliest} - ${latest}`;}
Advanced Configuration
Section titled “Advanced Configuration”Custom Group Header Styling
Section titled “Custom Group Header Styling”You can customize the appearance of group headers by modifying the template function:
const customGroupTemplate = (h: any, props: any) => { const aggregationValue = getAggregationValue(props);
return h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', padding: '4px 8px', backgroundColor: '#f0f0f0', borderRadius: '4px' } }, [ h('span', { style: { fontWeight: 'bold' } }, props.name), h('span', { style: { fontSize: '12px', color: '#666' } }, `(${aggregationValue})`) ]);};
Conditional Aggregations
Section titled “Conditional Aggregations”You can apply different aggregation logic based on the column or group:
const conditionalAggregations = { price: (values: any[]) => { const prices = values.map(item => item.price); const sum = prices.reduce((a, b) => a + b, 0); const avg = sum / prices.length; return `Avg: $${avg.toFixed(2)}`; }};
Best Practices
Section titled “Best Practices”- Performance: Keep aggregation functions lightweight, especially with large datasets
- User Experience: Provide clear, meaningful aggregation labels
- Data Types: Ensure aggregation functions handle the correct data types
- Error Handling: Add validation for edge cases (empty arrays, null values)
- Accessibility: Use descriptive text for screen readers
Common Use Cases
Section titled “Common Use Cases”- Sales Reports: Group by region/category with revenue totals
- Inventory Management: Group by department with stock quantities
- Financial Data: Group by account type with balance summaries
- Project Management: Group by team with task counts and completion rates