the row type
the source rows (not changed)
row fields, column fields, values
Optional groupColumn: Partial<RowGroupColumnOptionsIf<T>> = {}label options of the group column (showCount, label)
Optional defaultRowHeight: number = 34row height in px
The identifier for one of the areas: header, body, footer. This property determines which area of the table this model represents.
// Creating an area model for the header
const headerModel = new AreaModel();
headerModel.areaIdent = "header";
// Checking which area a model represents
if (areaModel.areaIdent === "body") {
// This is a body area model
}
Protected cellProtected columnReadonly kindMarker for isAreaModelPivot (works across copies of the core). type stays "AreaModelTree".
Protected Readonly propertiesA model and controller for row checkbox selection. This property allows the area to support row selection via checkboxes.
// Creating a checkbox model for row selection
import { CheckboxModel } from "@guiexpert/table";
const bodyModel = new AreaModel();
bodyModel.areaIdent = "body";
bodyModel.rowSelectionModel = new CheckboxModel();
// Later, check if a row is selected
const isSelected = bodyModel.isRowChecked(5);
Readonly rowsProtected yProtected addProtected apply„Show values as“ of one tree row: percentages of the column total relate to the (filtered) leaf rows,
percentOfParentTotal, runningTotal, differenceFromPrevious and rank to the displayed siblings.
Protected arrayRow drag: false – the table does not move rows of a pivot table itself (pivot rows are aggregates). With
rowDragOptions.managed: false the app gets the events and decides.
always false
1.1.95
Changes the order of columns by moving a column from one position to another. This method is called when the user drags a column to a new position.
The index of the column to move
The index where the column should be moved to
// Move the second column (index 1) to the fourth position (index 3)
areaModel.changeColumnOrder(1, 3);
// Implementation example
changeColumnOrder(sourceColumnIndex: number, targetColumnIndex: number): void {
// Move the column in the internal data structure
this.arrayMove(this.columns, sourceColumnIndex, targetColumnIndex);
// Update any dependent data structures
this.arrayMove(this.cellRenderers, sourceColumnIndex, targetColumnIndex);
}
Sorts the rows of every level: by a value column by its values (empty cells last, in both directions), by the group column by key. A new pivot (TableApi.setPivotConfig) starts unsorted (the columns are different).
primary key first
false for an empty list
pivotBody.doSort([new SortItem(pivotBody.getColumnIndex([]), "desc")]); // by the total, largest first
tableApi.repaint();
Filters the source rows before the aggregation: predictFn gets your objects (as in a flat table), index and
array of the source rows. All cells and totals follow; rows without a matching source row disappear. Usually
called by tableApi.externalFilterChanged() with tableOptions.externalFilterFunction.
returns a truthy value for the rows to count
tableOptions.externalFilterFunction = (sale: Sale) => sale.produkt === "A";
tableApi.externalFilterChanged(); // Nord: Jan 100, Feb 120 · Süd: Jan 80, Feb 30
Protected genericProtected getThe rows of column aggregates in formulas (SUM([total])): the filtered row objects.
Protected getThe renderer of a „Show values as“ column without an own renderer: the text of getTextValueAt.
Protected getValue columns: the AggregateCellRenderer (text node); the group column: none (label as text).
The source rows behind a cell (drill-down): the rows of its row group and column key that the filter keeps.
index of the displayed body row
column index (the group column: all rows of the row group)
a new array in source order
pivotBody.getCellSourceRows(0, 1).map(s => s.umsatz); // [100, 50] – Nord, Jan
Returns the column span value for the cell at the specified row and column indices. A colspan value of N means the cell spans N columns horizontally. Values less than 2 are ignored (no spanning).
The index of the row
The index of the column
The colspan value (number of columns the cell spans)
// Check if a cell spans multiple columns
const colspan = headerAreaModel.getColspanAt(0, 0);
if (colspan > 1) {
console.log(`This header cell spans ${colspan} columns`);
}
// Implementation example for a model with column spanning
getColspanAt(rowIndex: number, columnIndex: number): number {
// Special case: first row, first column spans 3 columns
if (rowIndex === 0 && columnIndex === 0) return 3;
// No spanning for other cells
return 1;
}
The index of a value column (see getColumnProperty).
the column keys, [] = the total column
Optional value: string | number = 0the index or name of the value
the column index or -1
pivotBody.getColumnIndex(["Jan"]); // 1
What a column shows: a column key, a subtotal or a total, and which value.
column index
undefined for the group column (and row numbers)
pivotBody.getColumnInfo(1)?.column?.label; // "Jan"
The property of a value column – for tableApi.getColumnIndex(), sortByColumn(), setColumnWidth() …
the column keys from the top column field down, e.g. [2026, 1]; [] = the total column
Optional value: string | number = 0the index or name of the value
the property, undefined if there is no such column
tableApi.sortByColumn(pivotBody.getColumnProperty([])!, "desc"); // rows by their total, largest first
The current configuration.
a copy
pivotBody.getConfig().columnFields; // ["monat"]
Returns an array of CSS class names to apply to the cell at the specified row and column indices. This method allows for custom styling of individual cells.
The index of the row
The index of the column
An array of CSS class names
// Apply custom classes to cells
const classes = bodyAreaModel.getCustomClassesAt(1, 2);
console.log(`Cell classes: ${classes.join(', ')}`);
// Implementation example with conditional styling
getCustomClassesAt(rowIndex: number, columnIndex: number): string[] {
const classes: string[] = [];
// Add classes based on row index
if (rowIndex % 2 === 0) {
classes.push('even-row');
} else {
classes.push('odd-row');
}
// Add classes based on cell value
const value = this.getValueAt(rowIndex, columnIndex);
if (typeof value === 'number' && value < 0) {
classes.push('negative-value');
}
// Add classes for selected rows
if (this.isRowChecked(rowIndex)) {
classes.push('selected-row');
}
return classes;
}
Returns an object containing CSS style properties to apply to the cell at the specified row and column indices. This method allows for inline styling of individual cells.
The index of the row
The index of the column
An object with CSS style properties, or undefined if no custom styles
// Apply custom styles to cells
const styles = bodyAreaModel.getCustomStyleAt(1, 2);
console.log('Cell styles:', styles);
// Implementation example with conditional styling
getCustomStyleAt(rowIndex: number, columnIndex: number): { [key: string]: string } | undefined {
// Apply background color based on value
const value = this.getValueAt(rowIndex, columnIndex);
if (typeof value === 'number') {
// Color gradient based on value
if (value < 0) {
return { 'background-color': `rgba(255, 0, 0, ${Math.min(Math.abs(value) / 100, 0.5)})` };
} else if (value > 0) {
return { 'background-color': `rgba(0, 255, 0, ${Math.min(value / 100, 0.5)})` };
}
}
return undefined; // No custom styles
}
The displayed children of a row (in display order): all children, with an active filter only those that match
(or have a matching descendant). They are on screen if the row is expanded.
Used for the screen reader attributes aria-setsize / aria-posinset of tree rows.
a tree row of this model
the displayed children (empty for a leaf)
const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
const shown = treeModel.getDisplayedChildren(treeModel.rows[0]).length;
1.1.91
Protected getThe label of a row in the group column.
The leaves (rows without children) of the whole tree, depth-first in the current order – independent of the expanded state. Used for totals: collapsing a node does not change them, and parent rows are not counted twice.
Optional filtered: boolean = trueonly the leaves the active filter keeps (externalFilterChanged); false: all
a new array
const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
const total = aggregate(treeModel.getLeafRows(), row => row.data.total, "sum");
1.1.94
Returns the maximum colspan value that can occur in this area model. This value is used to optimize rendering performance.
The maximum possible colspan value in this area
// Get the maximum colspan for optimization
const maxColspan = headerAreaModel.getMaxColspan();
// Implementation example
getMaxColspan(): number {
// If the model has no colspans, return 0 for optimization
return 0;
// If the model has colspans, return the maximum possible value
// return 3; // If some cells span up to 3 columns
}
Returns the maximum rowspan value that can occur in this area model. This value is used to optimize rendering performance.
The maximum possible rowspan value in this area
// Get the maximum rowspan for optimization
const maxRowspan = bodyAreaModel.getMaxRowspan();
// Implementation example
getMaxRowspan(): number {
// If the model has no rowspans, return 0 for optimization
return 0;
// If the model has rowspans, return the maximum possible value
// return 2; // If some cells span up to 2 rows
}
The property of a column (follows moved columns).
column index
the property, e.g. RowGroupColumnDef.PROPERTY for the group column
pivotBody.getPropertyAt(0); // "RowGroupColumn"
Protected getThe value of a tree row for a property – before „Show values as“: the computed value of a calculated column,
otherwise the property (path) of row.data. Subclasses (row groups) return their aggregates for group rows.
the tree row
the property of the column
the raw value
1.1.95
The pivot: row and column hierarchies and all values (also subtotals and totals) – for drill-down, own evaluations or a chart next to the table.
the result (do not modify)
const result = pivotBody.getResult();
result.columnLeaves.map(c => c.label); // ["Jan", "Feb"]
result.getValue(); // 450
Returns the row object at the specified index. This method provides access to the underlying data structure.
The index of the row
The row object
// Get a row object
const row = bodyAreaModel.getRowByIndex(1);
console.log('Row data:', row);
// Implementation example for an array-based model
getRowByIndex(rowIndex: number): any {
if (rowIndex < 0 || rowIndex >= this.data.length) return undefined;
return this.data[rowIndex];
}
Returns the number of rows in this area. This is a fundamental method that determines the vertical size of the area.
The number of rows in the area
// Get the number of rows in the body area
const rowCount = bodyAreaModel.getRowCount();
console.log(`The body has ${rowCount} rows`);
// Implementation example for an array-based model
getRowCount(): number {
return this.data.length;
}
The row group of a displayed row.
index of the displayed body row
the group, undefined for the total row of a pivot without row fields
pivotBody.getRowGroup(0)?.path; // ["Nord"]
Returns the height of the row at the specified index, in pixels. This method allows for variable row heights in the table.
The index of the row
The height of the row in pixels
// Get the height of a row
const height = bodyAreaModel.getRowHeight(1);
console.log(`Row 1 height: ${height}px`);
// Implementation example with fixed row height
getRowHeight(rowIndex: number): number {
return this.defaultRowHeight; // e.g., 30px
}
// Implementation example with variable row heights
getRowHeight(rowIndex: number): number {
// First row is taller
if (rowIndex === 0) return 50;
// Rows with more content are taller
const row = this.getRowByIndex(rowIndex);
if (row && row.hasLongContent) return 60;
// Default height for other rows
return 30;
}
The value of a column for a row object – the computed value of a calculated column, otherwise the property
(path). A TreeRow is unwrapped. The table API offers it as TableApi.getRowValue.
a row object (or TreeRow)
the property of the column
the value
const body = tableModel.getBodyModel() as AreaModelObjectArray<Item>;
body.getRowValue({ price: 25, quantity: 10 }, "total"); // 250
1.1.95
Returns the row span value for the cell at the specified row and column indices. A rowspan value of N means the cell spans N rows vertically. Values less than 2 are ignored (no spanning).
The index of the row
The index of the column
The rowspan value (number of rows the cell spans)
// Check if a cell spans multiple rows
const rowspan = bodyAreaModel.getRowspanAt(0, 0);
if (rowspan > 1) {
console.log(`This cell spans ${rowspan} rows`);
}
// Implementation example for a model with row spanning
getRowspanAt(rowIndex: number, columnIndex: number): number {
// Special case: first column spans 2 rows at the beginning
if (columnIndex === 0 && rowIndex % 2 === 0) return 2;
// No spanning for other cells
return 1;
}
The value of a pivot cell as shown: the aggregate, or with „Show values as“ (PivotValueIf.showValuesAs) its share of the row total, column total, grand total or parent row.
the row group; undefined = all rows (the total row)
the column (getColumnInfo)
the shown value, undefined for an empty cell
const body = (tableModel as PivotTableModel).getPivotBody();
body.getShownValue(body.getRowGroup(0), body.getColumnInfo(2)!); // 0.4 – 40 % of the row
1.1.95
Returns the value of the cell at the specified row and column indices. This is one of the most important methods in the area model, as it provides the actual data to be displayed in each cell.
The index of the row
The index of the column
The value at the specified cell
// Get the value of a cell
const value = bodyAreaModel.getValueAt(1, 2);
console.log(`Cell (1,2) contains: ${value}`);
// Implementation example for a 2D array model
getValueAt(rowIndex: number, columnIndex: number): any {
if (rowIndex < 0 || rowIndex >= this.data.length) return undefined;
const row = this.data[rowIndex];
if (columnIndex < 0 || columnIndex >= row.length) return undefined;
return row[columnIndex];
}
// Implementation example for an object array model
getValueAt(rowIndex: number, columnIndex: number): any {
const row = this.getRowByIndex(rowIndex);
if (!row) return undefined;
const property = this.columnDefs[columnIndex].property;
return row[property];
}
Returns the Y-coordinate (in pixels) of the top of the row at the specified index. This method is used for scrolling and positioning rows in the viewport.
The index of the row
The Y-coordinate of the top of the row, in pixels
// Get the Y-position of a row
const yPos = bodyAreaModel.getYPosByRowIndex(10);
console.log(`Row 10 starts at Y-position: ${yPos}px`);
// Implementation example with fixed row heights
getYPosByRowIndex(rowIndex: number): number {
return rowIndex * this.defaultRowHeight;
}
// Implementation example with variable row heights
getYPosByRowIndex(rowIndex: number): number {
// Use a pre-calculated array of Y-positions
return this.yPositions[rowIndex];
// Or calculate on-the-fly
// let yPos = 0;
// for (let i = 0; i < rowIndex; i++) {
// yPos += this.getRowHeight(i);
// }
// return yPos;
}
True if the row has children that are shown when it is expanded – with an active filter only children that match (or have a matching descendant) count. The arrow of a row without such children is hidden.
a tree row of this model
true if the row has displayed children
Initializes the area model. This method is called internally by the TableModel during initialization. It can be used to perform any necessary setup, such as calculating row positions.
// Implementation example
init(): void {
// Calculate y-positions for all rows
this.calculateYPositions();
// Initialize any other internal state
this.initialized = true;
}
Protected invalidateTrue if a column of this model with this property is calculated (valueGetter or formula).
the property of the column
whether its values are computed
tableModel.getBodyModel().isCalculatedProperty?.("total"); // true
1.1.95
Determines whether this area supports filtering. If true, the area can be filtered using the externalFilterChanged method.
True if the area is filterable, false otherwise
// Check if an area is filterable
const filterable = bodyAreaModel.isFilterable();
if (filterable) {
console.log('This area supports filtering');
}
// Implementation example
isFilterable(): boolean {
// Only the body area is filterable
return this.areaIdent === 'body';
}
Determines whether the row at the specified index is checkable. If true, a checkbox will be rendered at the beginning of the row.
The index of the row
True if the row is checkable, false otherwise
// Check if a row is checkable
const checkable = bodyAreaModel.isRowCheckable(1);
if (checkable) {
console.log('This row can be checked by the user');
}
// Implementation example
isRowCheckable(rowIndex: number): boolean {
// All rows are checkable by default
return true;
// Or implement custom logic
// const row = this.getRowByIndex(rowIndex);
// return row && !row.locked; // Only unlocked rows are checkable
}
Returns the checked state of the row at the specified index.
The index of the row
The checked state of the row (true, false, or 'indeterminate'), or undefined if the row is not checkable
// Check if a row is checked
const checkedState = bodyAreaModel.isRowChecked(1);
if (checkedState === "full") {
console.log('This row is checked');
} else if (checkedState === "semi") {
console.log('This row is partially checked');
}
// Implementation example using a row selection model
isRowChecked(rowIndex: number): CheckedType | undefined {
if (!this.rowSelectionModel) return undefined;
const row = this.getRowByIndex(rowIndex);
return this.rowSelectionModel.isRowChecked(row);
}
Determines whether the cell at the specified row and column indices is selectable.
If true, the user can select the cell: the table draws the selection only on selectable body cells.
All built-in models and AreaModel return true (except the hidden and cover-grid models).
The index of the row
The index of the column
True if the cell is selectable, false otherwise
// Check if a cell is selectable
const selectable = bodyAreaModel.isSelectable(1, 2);
if (selectable) {
console.log('This cell can be selected by the user');
}
// Implementation example
isSelectable(rowIndex: number, columnIndex: number): boolean {
// All cells are selectable by default
return true;
// Or implement custom logic
// return this.areaIdent === 'body'; // Only body cells are selectable
}
Row drag: does nothing (see canMoveRows).
always false
1.1.95
Protected readRebuilds the displayed rows after the expanded state of rows has changed and applies the active filter
(see externalFilterChanged) again. The table calls it on every expand/collapse click. Call it
yourself after changing row.expanded from code, then repaint with tableApi.repaintHard()
(the row count changes).
Optional refilter: boolean = truerun the filter function again (needed after the rows changed). false after a
pure expand/collapse: whether a row matches does not depend on it (the table does this on every click –
before, the filter ran over all nodes for each click).
// expand all first-level rows from code
const treeModel = tableModel.getBodyModel() as AreaModelTree<OrderNode>;
for (const row of treeModel.rows) row.expanded = true;
treeModel.recalcVisibleTreeRows();
tableApi.repaintHard();
Protected setWrites an edited value of a calculated column through its valueSetter; without one: rejected.
Protected setSets the checked state of the row at the specified index.
The index of the row
The new checked state
// Check a row
bodyAreaModel.setRowChecked(1, true);
// Uncheck a row
bodyAreaModel.setRowChecked(2, false);
// Implementation example using a row selection model
setRowChecked(rowIndex: number, checked: boolean): void {
if (!this.rowSelectionModel) return;
const row = this.getRowByIndex(rowIndex);
if (row) {
this.rowSelectionModel.checkRow(row, checked);
}
}
Sorts the rows of every level with your function – it gets two RowGroupIf (siblings).
compares two row groups
tableApi.sort((a: RowGroupIf, b: RowGroupIf) => b.count - a.count); // most source rows first
The body of a pivot table: one row per row group (a tree for several row fields, with subtotals in the group rows), one column per column key × value, plus subtotal and total columns. Created by PivotFactory.createTableModel – the factory also builds the grouped header and the total row.
It is a tree (AreaModelTree,
isAreaModelTreeis true): rows are tree rows with a RowGroupIf asdata; expanding,tableApi.expandAll(), keyboard, screen reader attributes and remembering expanded rows work as in a tree table. The cells come from a PivotResult (getResult).externalFilterFunctiongets your source objects (as in a flat table and a row grouping) – it filters before the aggregation; all cells and totals follow. Rows without a matching source row disappear; the columns stay (they come from all rows).tableApi.sort(fn)compares two RowGroupIf.tableApi.repaint()(same keys), new keys or fields: TableApi.setPivotConfig.Example
See
Training: Pivot tables
Since
1.1.94