Skip to content

Aggregates

Pantanal Grid supports aggregate calculations (sum, avg, min, max, count) displayed in group footers or column footers.

Basic Aggregates

Calculate sum, average, and count for numeric fields.

ID
Name
Price
Stock
1
Product A
$99.99
50
2
Product B
$49.99
100
3
Product C
$19.99
25
4
Product D
$79.99
75

Group Footers with Aggregates

Display aggregates in group footer rows when using grouping.

Category
ID
Name
Category
Price
Stock
Category: Clothing
Category: Electronics

Custom Group Footer Templates

Customize how aggregates are displayed using templates.

Category
ID
Name
Category
Price
Stock
Category: Clothing
Category: Electronics

All Aggregate Types

Showing only Sum in the table footer. Other aggregates can be displayed outside the table.

ID
Name
Price
Stock
1
Product A
$99.99
50
2
Product B
$49.99
100
3
Product C
$19.99
25
4
Product D
$79.99
75

Exemplo Traduzido (Português)

Labels dos aggregates traduzidos automaticamente conforme o locale.

ID
Nome
Preço
Estoque
1
Produto A
R$ 99.99
50
2
Produto B
R$ 49.99
100
3
Produto C
R$ 19.99
25
4
Produto D
R$ 79.99
75

Basic Aggregates

Category
ID
Name
Category
Price
Stock
Category: Clothing
Category: Electronics

Calculate aggregates for numeric fields:

vue
<script setup lang="ts">
import { ref } from 'vue'
import { PantanalGrid, type ColumnDef, type AggregateName } from '@pantanal/grid'

const rows = ref([
  { id: 1, name: 'Product A', price: 99.99, stock: 50 },
  { id: 2, name: 'Product B', price: 49.99, stock: 100 },
  { id: 3, name: 'Product C', price: 19.99, stock: 25 }
])

const columns: ColumnDef[] = [
  { field: 'id', title: 'ID', width: 80 },
  { field: 'name', title: 'Name' },
  { field: 'price', title: 'Price', format: (v: number) => `$${v.toFixed(2)}` },
  { field: 'stock', title: 'Stock' }
]

const aggregates: Record<string, AggregateName[]> = {
  price: ['sum', 'avg'],
  stock: ['sum'],
  id: ['count']
}
</script>

<template>
  <PantanalGrid
    :rows="rows"
    :columns="columns"
    key-field="id"
    :aggregates="aggregates"
  />
</template>

Group Footers with Aggregates

Display aggregates in group footer rows:

vue
<script setup lang="ts">
import { ref } from 'vue'
import { PantanalGrid, type ColumnDef, type GroupDescriptor, type AggregateName } from '@pantanal/grid'

const rows = ref([
  { id: 1, name: 'Product A', category: 'Electronics', price: 99.99, stock: 50 },
  { id: 2, name: 'Product B', category: 'Electronics', price: 49.99, stock: 100 },
  { id: 3, name: 'Product C', category: 'Clothing', price: 19.99, stock: 25 }
])

const columns: ColumnDef[] = [
  { field: 'id', title: 'ID', width: 80 },
  { field: 'name', title: 'Name' },
  { field: 'category', title: 'Category' },
  { field: 'price', title: 'Price', format: (v: number) => `$${v.toFixed(2)}` },
  { field: 'stock', title: 'Stock' }
]

const group = ref<GroupDescriptor[]>([
  { field: 'category', dir: 'asc' }
])

const aggregates: Record<string, AggregateName[]> = {
  price: ['sum', 'avg'],
  stock: ['sum'],
  id: ['count']
}
</script>

<template>
  <PantanalGrid
    :rows="rows"
    :columns="columns"
    key-field="id"
    :group="group"
    :aggregates="aggregates"
    :show-group-footers="true"
  />
</template>

Customize how aggregates are displayed:

vue
<script setup lang="ts">
const columns: ColumnDef[] = [
  { field: 'id', title: 'ID', width: 80 },
  { field: 'name', title: 'Name' },
  { field: 'category', title: 'Category' },
  { 
    field: 'price', 
    title: 'Price',
    aggregates: ['sum', 'avg'],
    format: (v: number) => `$${v.toFixed(2)}`,
    groupFooterTemplate: (group) => {
      const priceAgg = group.aggregates?.price
      if (priceAgg) {
        const sum = priceAgg.sum ?? 0
        const avg = priceAgg.avg ?? 0
        return `<strong style="color: #3b82f6;">Total: $${sum.toFixed(2)} | Avg: $${avg.toFixed(2)}</strong>`
      }
      return ''
    }
  },
  { 
    field: 'stock', 
    title: 'Stock',
    aggregates: ['sum', 'min', 'max'],
    groupFooterTemplate: (group) => {
      const stockAgg = group.aggregates?.stock
      if (stockAgg) {
        return `Sum: ${stockAgg.sum} | Min: ${stockAgg.min} | Max: ${stockAgg.max}`
      }
      return ''
    }
  }
]
</script>

Column-Level Aggregates

Define aggregates per column:

vue
<script setup lang="ts">
const columns: ColumnDef[] = [
  { field: 'id', title: 'ID', width: 80 },
  { field: 'name', title: 'Name' },
  { 
    field: 'price', 
    title: 'Price',
    aggregates: ['sum', 'avg'],  // Column-level aggregates
    format: (v: number) => `$${v.toFixed(2)}`
  },
  { 
    field: 'stock', 
    title: 'Stock',
    aggregates: ['sum', 'min', 'max']
  }
]
</script>

All Aggregate Types

Use all available aggregate functions:

vue
<script setup lang="ts">
const aggregates: Record<string, AggregateName[]> = {
  price: ['sum', 'avg', 'min', 'max'],
  stock: ['sum', 'avg', 'min', 'max', 'count'],
  id: ['count']
}
</script>

Multi-Level Grouping with Aggregates

Aggregates work with multi-level grouping:

vue
<script setup lang="ts">
const rows = ref([
  { id: 1, name: 'Product A', category: 'Electronics', brand: 'Brand X', price: 99.99, stock: 50 },
  { id: 2, name: 'Product B', category: 'Electronics', brand: 'Brand X', price: 49.99, stock: 100 },
  { id: 3, name: 'Product C', category: 'Electronics', brand: 'Brand Y', price: 19.99, stock: 25 },
  { id: 4, name: 'Product D', category: 'Clothing', brand: 'Brand X', price: 39.99, stock: 75 }
])

const group = ref<GroupDescriptor[]>([
  { field: 'category', dir: 'asc' },
  { field: 'brand', dir: 'asc' }
])

const aggregates: Record<string, AggregateName[]> = {
  price: ['sum', 'avg'],
  stock: ['sum'],
  id: ['count']
}
</script>

<template>
  <PantanalGrid
    :rows="rows"
    :columns="columns"
    key-field="id"
    :group="group"
    :aggregates="aggregates"
    :show-group-footers="true"
  />
</template>

Display aggregates in column footers (when not grouped):

vue
<script setup lang="ts">
const columns: ColumnDef[] = [
  { 
    field: 'price', 
    title: 'Price',
    aggregates: ['sum', 'avg'],
    format: (v: number) => `$${v.toFixed(2)}`,
    footerTemplate: (aggregates) => {
      const priceAgg = aggregates.price
      if (priceAgg) {
        const sum = priceAgg.sum ?? 0
        const avg = priceAgg.avg ?? 0
        return `<strong>Total: $${sum.toFixed(2)} | Avg: $${avg.toFixed(2)}</strong>`
      }
      return ''
    }
  }
]
</script>

Complete Example

vue
<script setup lang="ts">
import { ref } from 'vue'
import { PantanalGrid, type ColumnDef, type GroupDescriptor, type AggregateName } from '@pantanal/grid'

const rows = ref([
  { id: 1, name: 'Product A', category: 'Electronics', brand: 'Brand X', price: 99.99, stock: 50, units: 10 },
  { id: 2, name: 'Product B', category: 'Electronics', brand: 'Brand X', price: 49.99, stock: 100, units: 5 },
  { id: 3, name: 'Product C', category: 'Electronics', brand: 'Brand Y', price: 19.99, stock: 25, units: 20 },
  { id: 4, name: 'Product D', category: 'Clothing', brand: 'Brand X', price: 39.99, stock: 75, units: 15 },
  { id: 5, name: 'Product E', category: 'Clothing', brand: 'Brand Z', price: 29.99, stock: 200, units: 8 }
])

const columns: ColumnDef[] = [
  { field: 'id', title: 'ID', width: 80 },
  { field: 'name', title: 'Product Name' },
  { field: 'category', title: 'Category' },
  { field: 'brand', title: 'Brand' },
  { 
    field: 'price', 
    title: 'Price',
    aggregates: ['sum', 'avg'],
    format: (v: number) => `$${v.toFixed(2)}`,
    groupFooterTemplate: (group) => {
      const priceAgg = group.aggregates?.price
      if (priceAgg) {
        return `Sum: $${(priceAgg.sum ?? 0).toFixed(2)} | Avg: $${(priceAgg.avg ?? 0).toFixed(2)}`
      }
      return ''
    }
  },
  { 
    field: 'stock', 
    title: 'Stock',
    aggregates: ['sum', 'min', 'max'],
    groupFooterTemplate: (group) => {
      const stockAgg = group.aggregates?.stock
      if (stockAgg) {
        return `Sum: ${stockAgg.sum} | Min: ${stockAgg.min} | Max: ${stockAgg.max}`
      }
      return ''
    }
  },
  { 
    field: 'units', 
    title: 'Units',
    aggregates: ['count'],
    groupFooterTemplate: (group) => {
      const unitsAgg = group.aggregates?.units
      if (unitsAgg) {
        return `Count: ${unitsAgg.count}`
      }
      return ''
    }
  }
]

const group = ref<GroupDescriptor[]>([
  { field: 'category', dir: 'asc' },
  { field: 'brand', dir: 'asc' }
])

const aggregates: Record<string, AggregateName[]> = {
  price: ['sum', 'avg'],
  stock: ['sum', 'min', 'max'],
  units: ['count'],
  id: ['count']
}
</script>

<template>
  <PantanalGrid
    :rows="rows"
    :columns="columns"
    key-field="id"
    :group="group"
    :aggregates="aggregates"
    :show-group-footers="true"
    locale="en"
    responsive="table"
  />
</template>

Aggregate Functions Reference

sum

Calculates the sum of all numeric values in a field.

vue
const aggregates: Record<string, AggregateName[]> = {
  price: ['sum']
}

avg

Calculates the average (mean) of all numeric values in a field.

vue
const aggregates: Record<string, AggregateName[]> = {
  price: ['avg']
}

min

Finds the minimum value in a field.

vue
const aggregates: Record<string, AggregateName[]> = {
  price: ['min']
}

max

Finds the maximum value in a field.

vue
const aggregates: Record<string, AggregateName[]> = {
  price: ['max']
}

count

Counts the number of items (works with any data type).

vue
const aggregates: Record<string, AggregateName[]> = {
  id: ['count']
}

Use Cases

Financial Summary

vue
const aggregates: Record<string, AggregateName[]> = {
  revenue: ['sum'],
  cost: ['sum'],
  profit: ['sum', 'avg']
}

Inventory Management

vue
const aggregates: Record<string, AggregateName[]> = {
  stock: ['sum', 'min', 'max'],
  units: ['count'],
  price: ['avg']
}

Sales Analysis

vue
const aggregates: Record<string, AggregateName[]> = {
  sales: ['sum', 'avg'],
  quantity: ['sum', 'count'],
  price: ['min', 'max', 'avg']
}

See Also