# AdapTable for AG Grid
> AdapTable is a drop-in extension for AG Grid that turns it into a complete data application — layouts, querying, filtering, charting, styled columns, alerts, exports and more, out of the box.
Canonical page: https://www.adaptabletools.com/docs
#### What is AdapTable for AG Grid?
**AdapTable is a drop-in extension for [AG Grid](https://www.ag-grid.com/) that turns it into a complete data application — without you having to build one.**
Add AdapTable alongside your existing AG Grid instance and you immediately get layouts, querying, filtering, charting, styled columns, conditional formatting, exports, alerts, and dozens of other advanced features
- AG Grid is the best all-round JavaScript DataGrid on the market
- AdapTable builds on top of it without hiding or replacing any of its functionality
All the features that you would otherwise need to build bespoke for all your grids are available [out of the box](https://medium.com/ag-grid/getting-more-from-your-datagrid-introducing-adaptable-blotter-2be5debd7e46).
Everything your users do — sort, filter, format, customise — is persisted, shareable across teams, and fully configurable in code.
AdapTable only works with the **AG Grid Enterprise Version** as it extends many of that Grid's advanced features
### Vanilla
**Example: Introducing AdapTable**
How AdapTable integrates with - and extends - AG Grid
- This demo illustrates how AdapTable integrates with the excellent AG Grid providing additional, cutting-edge features for advanced users
- The dummy data it contains is used in most of the demos in this documentation and comes from Github
- The demo (like all examples) includes the 3 elements that are included in every AdapTable-based application (click on 'Show Code' to see more):
- [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md): objects created for first time use
- [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md): configuration settings and JavaScript functions
- [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md): providing run-time access to AdapTable functionality
- Each of these are explained in greater length in the demos and pages on this site
- Switch to 'Light Theme' in the Tool Panel to see AdapTable (and AG Grid) in the light theme
- Click on the `Show Code` button above the demo to see all the code used in this example, or `Fork` the demo to extend it
```ts
import {
AdaptableButton,
AdaptableOptions,
CustomColumnMenuContext,
CustomContextMenuContext,
CustomToolbarButtonContext,
DashboardButtonContext,
UserColumnMenuItem,
UserContextMenuItem,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Intro to AdapTable',
dashboardOptions: {
customToolbars: [
{
name: 'CustomToolbar',
title: 'Custom',
toolbarButtons: [
{
label: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
return context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? 'Switch to Dark Theme'
: 'Switch to Light Theme';
},
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? context.adaptableApi.themeApi.loadDarkTheme()
: context.adaptableApi.themeApi.loadLightTheme();
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
],
},
],
customDashboardButtons: [
{
label: 'Current Time',
onClick: (
button: AdaptableButton,
context: DashboardButtonContext
) => {
context.adaptableApi.alertApi.showAlertInfo(
'Current Time',
new Date().toTimeString()
);
},
buttonStyle: {
tone: 'info',
variant: 'text',
},
},
],
},
columnMenuOptions: {
customColumnMenu: (context: CustomColumnMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserColumnMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
contextMenuOptions: {
customContextMenu: (context: CustomContextMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserContextMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Demo',
// Surface the user-defined CustomToolbar on the default tab so
// the demo shows off a custom toolbar without the user having
// to click around.
Toolbars: ['Export', 'GridFilter', 'CustomToolbar'],
},
{
Name: 'Notifications',
Toolbars: ['Alert', 'SystemStatus'],
},
],
ModuleButtons: [
'FormatColumn',
'DataChangeHistory',
'CalculatedColumn',
'Shortcut',
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Export: {
CurrentReport: 'Popular Frameworks',
CurrentFormat: 'JSON',
Reports: [
{
ReportColumnScope: 'ScopeColumns',
ReportRowScope: 'ExpressionRows',
Scope: {ColumnIds: ['name', 'language']},
Query: {BooleanExpression: '[github_stars] > 50000 '},
Name: 'Popular Frameworks',
},
],
},
Layout: {
CurrentLayout: 'Sorted Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'week_issue_change',
'created_at',
'github_watchers',
'has_wiki',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
Name: 'Sorted Layout',
ColumnSorts: [
{
ColumnId: 'license',
SortOrder: 'Asc',
},
{
ColumnId: 'name',
SortOrder: 'Desc',
},
],
// Filter the grid to a focused set (~21 rows) so the column
// formatting / styled columns are immediately legible without
// scrolling. Bind any other expression in the Grid Filter
// toolbar to refine further.
GridFilter: {
Expression: '[github_stars] > 10000',
},
AutoSizeColumns: true,
},
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'open_issues_count',
'closed_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
Name: 'Grouping Layout',
RowGroupedColumns: ['language', 'license'],
TableAggregationColumns: [
{
ColumnId: 'open_issues_count',
AggFunc: 'sum',
},
{
ColumnId: 'closed_issues_count',
AggFunc: 'max',
},
],
AutoSizeColumns: true,
},
],
},
// Two column-scoped format columns add live styling on the column the
// user is looking at, paired with display formats so the raw numbers
// read more naturally. These deliberately target columns (rather than
// whole rows) so the table content stays the focal point.
FormatColumn: {
FormatColumns: [
{
Name: 'name-upper',
Scope: {ColumnIds: ['name']},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {Case: 'Upper', Trim: false},
},
},
{
Name: 'created-at-pattern',
Scope: {ColumnIds: ['created_at']},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {Pattern: 'yyyy/MM/dd'},
},
},
{
Name: 'github-stars-thousands',
Scope: {ColumnIds: ['github_stars']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {IntegerSeparator: ','},
},
},
{
Name: 'github-stars-highlight',
Scope: {ColumnIds: ['github_stars']},
Rule: {BooleanExpression: '[github_stars] > 100000'},
Style: {
FontWeight: 'Bold',
ForeColor: 'var(--ab-color-accent)',
},
},
{
Name: 'week-issue-change-parens',
Scope: {ColumnIds: ['week_issue_change']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {Parentheses: true},
},
},
{
Name: 'week-issue-change-positive',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] > 0'},
Style: {
ForeColor: 'var(--ab-color-success)',
FontWeight: 'Bold',
},
},
{
Name: 'week-issue-change-negative',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] < 0'},
Style: {
ForeColor: 'var(--ab-color-destructive)',
FontWeight: 'Bold',
},
},
],
},
// Two styled columns: language is rendered as a coloured pill that
// makes the stack instantly scannable; rating turns the new 1–5
// number into a row of stars.
StyledColumn: {
StyledColumns: [
{
Name: 'Language Badge',
ColumnId: 'language',
BadgeStyle: {
Badges: [
{
Predicate: {PredicateId: 'Is', Inputs: ['JavaScript']},
PillStyle: {BackColor: '#f7df1e', ForeColor: '#1a1a1a'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['TypeScript']},
PillStyle: {BackColor: '#3178c6', ForeColor: '#ffffff'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['HTML']},
PillStyle: {BackColor: '#e34c26', ForeColor: '#ffffff'},
},
],
},
},
{
Name: 'Rating',
ColumnId: 'rating',
RatingStyle: {
Icon: 'Star',
Max: 5,
Size: 14,
Gap: 2,
AllowHalf: true,
ShowValue: false,
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.toolPanelApi.openAdapTableToolPanel();
};
```
### Angular
#### What is AdapTable for AG Grid Angular?
AdapTable for AG Grid Angular is a lightweight wrapper around [AG Grid Angular](https://www.ag-grid.com/angular-data-grid/getting-started/).
It enables AdapTable to be **instantiated** and referenced inside an Angular application, and used, in a recognisably **Angular way**.
AdapTable supports whichever versions of Angular are being supported by AG Grid; currently that is **Angular 18 - 21**
It integrates directly with, and extends, the AG Grid Angular Component, and enables [Angular Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md) to be provided to AdapTable in a framework-friendly fashion.
- Other than [Installation](https://www.adaptabletools.com/docs/angular-installation/index.md) & [Integration](https://www.adaptabletools.com/docs/angular-integration/index.md), everything you do in AdapTable Angular is the same as AdapTable Vanilla
- e.g. create [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md), write [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) and use the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) etc.
**Example: Introducing AdapTable**
How AdapTable integrates with - and extends - AG Grid
- This demo illustrates how AdapTable for Angular integrates with the excellent AG Grid providing additional, cutting-edge features for advanced users.
- The dummy data it contains is used in most of the demos in this documentation and comes from Github.
- The demo includes the 3 elements that are typically included in every AdapTable-based application (click on 'Show Code' to see more):
- [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md): objects created for first time use
- [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md): configuration settings and JavaScript functions
- [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md): providing run-time access to AdapTable functionality
- Each of these are explained in greater length in the demos and pages on this site.
- Switch to 'Light Theme' in the Tool Panel to see AdapTable (and AG Grid) in the light theme
- Click on the `Show Code` button above the demo to see all the code used in this example, or `Fork` the demo to extend it
```ts
import {
AdaptableButton,
AdaptableOptions,
CustomColumnMenuContext,
CustomContextMenuContext,
CustomToolbarButtonContext,
DashboardButtonContext,
UserColumnMenuItem,
UserContextMenuItem,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Intro to AdapTable',
dashboardOptions: {
customToolbars: [
{
name: 'CustomToolbar',
title: 'Custom',
toolbarButtons: [
{
label: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
return context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? 'Switch to Dark Theme'
: 'Switch to Light Theme';
},
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? context.adaptableApi.themeApi.loadDarkTheme()
: context.adaptableApi.themeApi.loadLightTheme();
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
],
},
],
customDashboardButtons: [
{
label: 'Current Time',
onClick: (
button: AdaptableButton,
context: DashboardButtonContext
) => {
context.adaptableApi.alertApi.showAlertInfo(
'Current Time',
new Date().toTimeString()
);
},
buttonStyle: {
tone: 'info',
variant: 'text',
},
},
],
},
columnMenuOptions: {
customColumnMenu: (context: CustomColumnMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserColumnMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
contextMenuOptions: {
customContextMenu: (context: CustomContextMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserContextMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Demo',
// Surface the user-defined CustomToolbar on the default tab so
// the demo shows off a custom toolbar without the user having
// to click around.
Toolbars: ['Export', 'GridFilter', 'CustomToolbar'],
},
{
Name: 'Notifications',
Toolbars: ['Alert', 'SystemStatus'],
},
],
ModuleButtons: [
'FormatColumn',
'DataChangeHistory',
'CalculatedColumn',
'Shortcut',
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Export: {
CurrentReport: 'Popular Frameworks',
CurrentFormat: 'JSON',
Reports: [
{
ReportColumnScope: 'ScopeColumns',
ReportRowScope: 'ExpressionRows',
Scope: {ColumnIds: ['name', 'language']},
Query: {BooleanExpression: '[github_stars] > 50000 '},
Name: 'Popular Frameworks',
},
],
},
Layout: {
CurrentLayout: 'Sorted Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'week_issue_change',
'created_at',
'github_watchers',
'has_wiki',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
Name: 'Sorted Layout',
ColumnSorts: [
{
ColumnId: 'license',
SortOrder: 'Asc',
},
{
ColumnId: 'name',
SortOrder: 'Desc',
},
],
// Filter the grid to a focused set (~21 rows) so the column
// formatting / styled columns are immediately legible without
// scrolling. Bind any other expression in the Grid Filter
// toolbar to refine further.
GridFilter: {
Expression: '[github_stars] > 10000',
},
AutoSizeColumns: true,
},
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'open_issues_count',
'closed_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
Name: 'Grouping Layout',
RowGroupedColumns: ['language', 'license'],
TableAggregationColumns: [
{
ColumnId: 'open_issues_count',
AggFunc: 'sum',
},
{
ColumnId: 'closed_issues_count',
AggFunc: 'max',
},
],
AutoSizeColumns: true,
},
],
},
// Two column-scoped format columns add live styling on the column the
// user is looking at, paired with display formats so the raw numbers
// read more naturally. These deliberately target columns (rather than
// whole rows) so the table content stays the focal point.
FormatColumn: {
FormatColumns: [
{
Name: 'name-upper',
Scope: {ColumnIds: ['name']},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {Case: 'Upper', Trim: false},
},
},
{
Name: 'created-at-pattern',
Scope: {ColumnIds: ['created_at']},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {Pattern: 'yyyy/MM/dd'},
},
},
{
Name: 'github-stars-thousands',
Scope: {ColumnIds: ['github_stars']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {IntegerSeparator: ','},
},
},
{
Name: 'github-stars-highlight',
Scope: {ColumnIds: ['github_stars']},
Rule: {BooleanExpression: '[github_stars] > 100000'},
Style: {
FontWeight: 'Bold',
ForeColor: 'var(--ab-color-accent)',
},
},
{
Name: 'week-issue-change-parens',
Scope: {ColumnIds: ['week_issue_change']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {Parentheses: true},
},
},
{
Name: 'week-issue-change-positive',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] > 0'},
Style: {
ForeColor: 'var(--ab-color-success)',
FontWeight: 'Bold',
},
},
{
Name: 'week-issue-change-negative',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] < 0'},
Style: {
ForeColor: 'var(--ab-color-destructive)',
FontWeight: 'Bold',
},
},
],
},
// Two styled columns: language is rendered as a coloured pill that
// makes the stack instantly scannable; rating turns the new 1–5
// number into a row of stars.
StyledColumn: {
StyledColumns: [
{
Name: 'Language Badge',
ColumnId: 'language',
BadgeStyle: {
Badges: [
{
Predicate: {PredicateId: 'Is', Inputs: ['JavaScript']},
PillStyle: {BackColor: '#f7df1e', ForeColor: '#1a1a1a'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['TypeScript']},
PillStyle: {BackColor: '#3178c6', ForeColor: '#ffffff'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['HTML']},
PillStyle: {BackColor: '#e34c26', ForeColor: '#ffffff'},
},
],
},
},
{
Name: 'Rating',
ColumnId: 'rating',
RatingStyle: {
Icon: 'Star',
Max: 5,
Size: 14,
Gap: 2,
AllowHalf: true,
ShowValue: false,
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.toolPanelApi.openAdapTableToolPanel();
};
```
### React
#### What is AdapTable for AG Grid React?
AdapTable for AG Grid React is a lightweight wrapper around [AG Grid React](https://www.ag-grid.com/react-data-grid/getting-started/).
It enables AdapTable to be **instantiated** and referenced inside a React application, and used, in a recognisably **React way**.
AdapTable requires React 18 or 19 - please make sure you are using one of these React versions in your application
It integrates directly with, and extends, the AG Grid React Component, and enables [React Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md) to be provided to AdapTable in a framework-friendly fashion.
- Other than [Installation](https://www.adaptabletools.com/docs/angular-installation/index.md) & [Integration](https://www.adaptabletools.com/docs/angular-integration/index.md), everything you do in AdapTable React is the same as AdapTable Vanilla
- e.g. create [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md), write [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) and use the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) etc.
**Example: Introducing AdapTable**
How AdapTable integrates with - and extends - AG Grid
- This demo illustrates how AdapTable for React integrates with the excellent AG Grid providing additional, cutting-edge features for advanced users.
- The dummy data it contains is used in most of the demos in this documentation and comes from Github.
- The demo includes the 3 elements that are typically included in every AdapTable-based application (click on 'Show Code' to see more):
- [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md): objects created for first time use
- [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md): configuration settings and JavaScript functions
- [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md): providing run-time access to AdapTable functionality
- Each of these are explained in greater length in the demos and pages on this site.
- Switch to 'Light Theme' in the Tool Panel to see AdapTable (and AG Grid) in the light theme
- Click on the `Show Code` button above the demo to see all the code used in this example, or `Fork` the demo to extend it
```ts
import {
AdaptableButton,
AdaptableOptions,
CustomColumnMenuContext,
CustomContextMenuContext,
CustomToolbarButtonContext,
DashboardButtonContext,
UserColumnMenuItem,
UserContextMenuItem,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Intro to AdapTable',
dashboardOptions: {
customToolbars: [
{
name: 'CustomToolbar',
title: 'Custom',
toolbarButtons: [
{
label: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
return context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? 'Switch to Dark Theme'
: 'Switch to Light Theme';
},
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? context.adaptableApi.themeApi.loadDarkTheme()
: context.adaptableApi.themeApi.loadLightTheme();
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
],
},
],
customDashboardButtons: [
{
label: 'Current Time',
onClick: (
button: AdaptableButton,
context: DashboardButtonContext
) => {
context.adaptableApi.alertApi.showAlertInfo(
'Current Time',
new Date().toTimeString()
);
},
buttonStyle: {
tone: 'info',
variant: 'text',
},
},
],
},
columnMenuOptions: {
customColumnMenu: (context: CustomColumnMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserColumnMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
contextMenuOptions: {
customContextMenu: (context: CustomContextMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserContextMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Demo',
// Surface the user-defined CustomToolbar on the default tab so
// the demo shows off a custom toolbar without the user having
// to click around.
Toolbars: ['Export', 'GridFilter', 'CustomToolbar'],
},
{
Name: 'Notifications',
Toolbars: ['Alert', 'SystemStatus'],
},
],
ModuleButtons: [
'FormatColumn',
'DataChangeHistory',
'CalculatedColumn',
'Shortcut',
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Export: {
CurrentReport: 'Popular Frameworks',
CurrentFormat: 'JSON',
Reports: [
{
ReportColumnScope: 'ScopeColumns',
ReportRowScope: 'ExpressionRows',
Scope: {ColumnIds: ['name', 'language']},
Query: {BooleanExpression: '[github_stars] > 50000 '},
Name: 'Popular Frameworks',
},
],
},
Layout: {
CurrentLayout: 'Sorted Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'week_issue_change',
'created_at',
'github_watchers',
'has_wiki',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
Name: 'Sorted Layout',
ColumnSorts: [
{
ColumnId: 'license',
SortOrder: 'Asc',
},
{
ColumnId: 'name',
SortOrder: 'Desc',
},
],
// Filter the grid to a focused set (~21 rows) so the column
// formatting / styled columns are immediately legible without
// scrolling. Bind any other expression in the Grid Filter
// toolbar to refine further.
GridFilter: {
Expression: '[github_stars] > 10000',
},
AutoSizeColumns: true,
},
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'open_issues_count',
'closed_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
Name: 'Grouping Layout',
RowGroupedColumns: ['language', 'license'],
TableAggregationColumns: [
{
ColumnId: 'open_issues_count',
AggFunc: 'sum',
},
{
ColumnId: 'closed_issues_count',
AggFunc: 'max',
},
],
AutoSizeColumns: true,
},
],
},
// Two column-scoped format columns add live styling on the column the
// user is looking at, paired with display formats so the raw numbers
// read more naturally. These deliberately target columns (rather than
// whole rows) so the table content stays the focal point.
FormatColumn: {
FormatColumns: [
{
Name: 'name-upper',
Scope: {ColumnIds: ['name']},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {Case: 'Upper', Trim: false},
},
},
{
Name: 'created-at-pattern',
Scope: {ColumnIds: ['created_at']},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {Pattern: 'yyyy/MM/dd'},
},
},
{
Name: 'github-stars-thousands',
Scope: {ColumnIds: ['github_stars']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {IntegerSeparator: ','},
},
},
{
Name: 'github-stars-highlight',
Scope: {ColumnIds: ['github_stars']},
Rule: {BooleanExpression: '[github_stars] > 100000'},
Style: {
FontWeight: 'Bold',
ForeColor: 'var(--ab-color-accent)',
},
},
{
Name: 'week-issue-change-parens',
Scope: {ColumnIds: ['week_issue_change']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {Parentheses: true},
},
},
{
Name: 'week-issue-change-positive',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] > 0'},
Style: {
ForeColor: 'var(--ab-color-success)',
FontWeight: 'Bold',
},
},
{
Name: 'week-issue-change-negative',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] < 0'},
Style: {
ForeColor: 'var(--ab-color-destructive)',
FontWeight: 'Bold',
},
},
],
},
// Two styled columns: language is rendered as a coloured pill that
// makes the stack instantly scannable; rating turns the new 1–5
// number into a row of stars.
StyledColumn: {
StyledColumns: [
{
Name: 'Language Badge',
ColumnId: 'language',
BadgeStyle: {
Badges: [
{
Predicate: {PredicateId: 'Is', Inputs: ['JavaScript']},
PillStyle: {BackColor: '#f7df1e', ForeColor: '#1a1a1a'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['TypeScript']},
PillStyle: {BackColor: '#3178c6', ForeColor: '#ffffff'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['HTML']},
PillStyle: {BackColor: '#e34c26', ForeColor: '#ffffff'},
},
],
},
},
{
Name: 'Rating',
ColumnId: 'rating',
RatingStyle: {
Icon: 'Star',
Max: 5,
Size: 14,
Gap: 2,
AllowHalf: true,
ShowValue: false,
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.toolPanelApi.openAdapTableToolPanel();
};
```
### React Hooks
AdapTable React provides [3 custom React hooks](https://www.adaptabletools.com/docs/react-adaptable-hooks/index.md) which you can use in your React components, enabling you to interact with [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md), the current [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) and the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) in a more natural React-way.
- `useAdaptableState`
- `useCurrentLayout`
- `useAdaptableApi`
### Vue
#### What is AdapTable for AG Grid Vue?
AdapTable for AG Grid Vue is a lightweight wrapper around [AG Grid Vue](https://www.ag-grid.com/vue-data-grid/getting-started/).
It enables AdapTable to be **instantiated** and referenced inside a Vue application, and used, in a recognisably **Vue way**.
- AdapTable requires **Vue 3** - please make sure you are using this version of Vue in your own application
- This is because AG Grid (from v.32+) [only supports Vue 3](https://ag-grid.com/vue-data-grid/compatibility/)
It integrates directly with, and extends, the AG Grid Vue Component, and enables [Vue Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md) to be provided to AdapTable in a framework-friendly fashion.
- Other than [Installation](https://www.adaptabletools.com/docs/angular-installation/index.md) & [Integration](https://www.adaptabletools.com/docs/angular-integration/index.md), everything you do in AdapTable Vue is the same as AdapTable Vanilla
- e.g. create [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md), write [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) and use the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) etc.
**Example: Introducing AdapTable**
How AdapTable integrates with - and extends - AG Grid
- This demo illustrates how AdapTable for Vue integrates with the excellent AG Grid providing additional, cutting-edge features for advanced users.
- The dummy data it contains is used in most of the demos in this documentation and comes from Github.
- The demo includes the 3 elements that are typically included in every AdapTable-based application (click on 'Show Code' to see more):
- [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md): objects created for first time use
- [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md): configuration settings and JavaScript functions
- [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md): providing run-time access to AdapTable functionality
- Each of these are explained in greater length in the demos and pages on this site.
- Switch to 'Light Theme' in the Tool Panel to see AdapTable (and AG Grid) in the light theme
- Click on the `Show Code` button above the demo to see all the code used in this example, or `Fork` the demo to extend it
```ts
import {
AdaptableButton,
AdaptableOptions,
CustomColumnMenuContext,
CustomContextMenuContext,
CustomToolbarButtonContext,
DashboardButtonContext,
UserColumnMenuItem,
UserContextMenuItem,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Intro to AdapTable',
dashboardOptions: {
customToolbars: [
{
name: 'CustomToolbar',
title: 'Custom',
toolbarButtons: [
{
label: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
return context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? 'Switch to Dark Theme'
: 'Switch to Light Theme';
},
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.themeApi.getCurrentTheme() == 'light'
? context.adaptableApi.themeApi.loadDarkTheme()
: context.adaptableApi.themeApi.loadLightTheme();
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
],
},
],
customDashboardButtons: [
{
label: 'Current Time',
onClick: (
button: AdaptableButton,
context: DashboardButtonContext
) => {
context.adaptableApi.alertApi.showAlertInfo(
'Current Time',
new Date().toTimeString()
);
},
buttonStyle: {
tone: 'info',
variant: 'text',
},
},
],
},
columnMenuOptions: {
customColumnMenu: (context: CustomColumnMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserColumnMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
contextMenuOptions: {
customContextMenu: (context: CustomContextMenuContext) => {
const {
defaultAgGridMenuStructure,
defaultAdaptableMenuStructure,
adaptableApi,
} = context;
const customDashboardMenuItem: UserContextMenuItem = {
menuType: 'User',
label: adaptableApi.dashboardApi.isDashboardCollapsed()
? 'Expand Dashboard'
: 'Collapse Dashboard',
onClick: () =>
adaptableApi.dashboardApi.isDashboardCollapsed()
? adaptableApi.dashboardApi.expandDashboard()
: adaptableApi.dashboardApi.collapseDashboard(),
};
return [
customDashboardMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Demo',
// Surface the user-defined CustomToolbar on the default tab so
// the demo shows off a custom toolbar without the user having
// to click around.
Toolbars: ['Export', 'GridFilter', 'CustomToolbar'],
},
{
Name: 'Notifications',
Toolbars: ['Alert', 'SystemStatus'],
},
],
ModuleButtons: [
'FormatColumn',
'DataChangeHistory',
'CalculatedColumn',
'Shortcut',
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Export: {
CurrentReport: 'Popular Frameworks',
CurrentFormat: 'JSON',
Reports: [
{
ReportColumnScope: 'ScopeColumns',
ReportRowScope: 'ExpressionRows',
Scope: {ColumnIds: ['name', 'language']},
Query: {BooleanExpression: '[github_stars] > 50000 '},
Name: 'Popular Frameworks',
},
],
},
Layout: {
CurrentLayout: 'Sorted Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'week_issue_change',
'created_at',
'github_watchers',
'has_wiki',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
Name: 'Sorted Layout',
ColumnSorts: [
{
ColumnId: 'license',
SortOrder: 'Asc',
},
{
ColumnId: 'name',
SortOrder: 'Desc',
},
],
// Filter the grid to a focused set (~21 rows) so the column
// formatting / styled columns are immediately legible without
// scrolling. Bind any other expression in the Grid Filter
// toolbar to refine further.
GridFilter: {
Expression: '[github_stars] > 10000',
},
AutoSizeColumns: true,
},
{
TableColumns: [
'name',
'language',
'github_stars',
'rating',
'license',
'open_issues_count',
'closed_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
Name: 'Grouping Layout',
RowGroupedColumns: ['language', 'license'],
TableAggregationColumns: [
{
ColumnId: 'open_issues_count',
AggFunc: 'sum',
},
{
ColumnId: 'closed_issues_count',
AggFunc: 'max',
},
],
AutoSizeColumns: true,
},
],
},
// Two column-scoped format columns add live styling on the column the
// user is looking at, paired with display formats so the raw numbers
// read more naturally. These deliberately target columns (rather than
// whole rows) so the table content stays the focal point.
FormatColumn: {
FormatColumns: [
{
Name: 'name-upper',
Scope: {ColumnIds: ['name']},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {Case: 'Upper', Trim: false},
},
},
{
Name: 'created-at-pattern',
Scope: {ColumnIds: ['created_at']},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {Pattern: 'yyyy/MM/dd'},
},
},
{
Name: 'github-stars-thousands',
Scope: {ColumnIds: ['github_stars']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {IntegerSeparator: ','},
},
},
{
Name: 'github-stars-highlight',
Scope: {ColumnIds: ['github_stars']},
Rule: {BooleanExpression: '[github_stars] > 100000'},
Style: {
FontWeight: 'Bold',
ForeColor: 'var(--ab-color-accent)',
},
},
{
Name: 'week-issue-change-parens',
Scope: {ColumnIds: ['week_issue_change']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {Parentheses: true},
},
},
{
Name: 'week-issue-change-positive',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] > 0'},
Style: {
ForeColor: 'var(--ab-color-success)',
FontWeight: 'Bold',
},
},
{
Name: 'week-issue-change-negative',
Scope: {ColumnIds: ['week_issue_change']},
Rule: {BooleanExpression: '[week_issue_change] < 0'},
Style: {
ForeColor: 'var(--ab-color-destructive)',
FontWeight: 'Bold',
},
},
],
},
// Two styled columns: language is rendered as a coloured pill that
// makes the stack instantly scannable; rating turns the new 1–5
// number into a row of stars.
StyledColumn: {
StyledColumns: [
{
Name: 'Language Badge',
ColumnId: 'language',
BadgeStyle: {
Badges: [
{
Predicate: {PredicateId: 'Is', Inputs: ['JavaScript']},
PillStyle: {BackColor: '#f7df1e', ForeColor: '#1a1a1a'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['TypeScript']},
PillStyle: {BackColor: '#3178c6', ForeColor: '#ffffff'},
},
{
Predicate: {PredicateId: 'Is', Inputs: ['HTML']},
PillStyle: {BackColor: '#e34c26', ForeColor: '#ffffff'},
},
],
},
},
{
Name: 'Rating',
ColumnId: 'rating',
RatingStyle: {
Icon: 'Star',
Max: 5,
Size: 14,
Gap: 2,
AllowHalf: true,
ShowValue: false,
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.toolPanelApi.openAdapTableToolPanel();
};
```
#### How does AdapTable work?
AdapTable extends AG Grid by providing a set of **complementary features** designed to meet advanced DataGrid use cases.
AdapTable provides full support for all AG Grid functionality including Modules, Pivoting, Master / Detail, Charts etc.
#### What can I do with AdapTable?
AdapTable ships with **over 150 features** that turn AG Grid into a fully-featured data application — without you having to write any of them.
Some of the more commonly used features include:
**Layout & Theme**
- [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) — save, switch and share named grid views
- [Pivots, Groups & Aggregations](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) for slicing and summarising data in-place
- [Theming](https://www.adaptabletools.com/docs/handbook-theming/index.md) with built-in light and dark themes
- Custom [Dashboards](https://www.adaptabletools.com/docs/ui-dashboard/index.md), [Tool Panels](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) and [Settings Panels](https://www.adaptabletools.com/docs/ui-settings-panel/index.md)
**Find & Filter**
- [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md) — type to highlight matches across the grid
- [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) and [Grid Filters](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md)
- [AdapTable Query Language](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) — an expressive, reactive expression engine
**Style & Format**
- [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) — Badges, Ratings, Sparklines, PercentBars, Gradients and more
- [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) for conditional styling and display formats
- [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) to draw the eye to live data changes
**Extend Your Data**
- [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) — formulae, aggregates and reactive expressions
- [FreeText Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) for user-editable annotations
- [Notes](https://www.adaptabletools.com/docs/handbook-notes/index.md) and [Comments](https://www.adaptabletools.com/docs/handbook-comments/index.md) attached to cells and rows
**Notify & Automate**
- [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) — rule-based, scheduled, or both
- [Exports](https://www.adaptabletools.com/docs/handbook-exporting/index.md) to Excel, CSV, JSON, Clipboard and OpenFin
- [Schedules](https://www.adaptabletools.com/docs/handbook-scheduling/index.md) for time-based actions and reports
**Collaborate & Control**
- [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md) — push named configurations to colleagues
- [Permissions & Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md)
- [Audit Log](https://www.adaptabletools.com/docs/dev-guide-support-monitoring/index.md) for compliance and support
- See the [Features List](https://www.adaptabletools.com/docs/getting-started-features-guide/index.md) for a comprehensive list of all features in AdapTable
- Visit the [Demos page](https://www.adaptabletools.com/docs/documentation-demo-list/index.md) to see all of these features running live
## Frameworks & Environment
#### Which frameworks are supported?
AdapTable comes in 4 flavours:
| Flavour | Framework Picker | Extends | Installation | Integration |
| ------------------------ | :--------------: | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- |
| **AdapTable TypeScript** | TypeScript | [AG Grid JavaScript](https://www.ag-grid.com/javascript-data-grid/) | [Installation](https://www.adaptabletools.com/docs/getting-started-installation/index.md) | [Integration](https://www.adaptabletools.com/docs/getting-started-integration/index.md) |
| **AdapTable React** | React | [AG Grid React](https://www.ag-grid.com/react-data-grid/getting-started/) | [Installation](https://www.adaptabletools.com/docs/react-installation/index.md) | [Integration](https://www.adaptabletools.com/docs/react-integration/index.md) |
| **AdapTable Angular** | Angular | [AG Grid Angular](https://www.ag-grid.com/angular-data-grid/getting-started/) | [Installation](https://www.adaptabletools.com/docs/angular-installation/index.md) | [Integration](https://www.adaptabletools.com/docs/angular-integration/index.md) |
| **AdapTable Vue** | Vue | [AG Grid Vue](https://www.ag-grid.com/vue-data-grid/getting-started/) | [Installation](https://www.adaptabletools.com/docs/vue-installation/index.md) | [Integration](https://www.adaptabletools.com/docs/vue-integration/index.md) |
- Use the **framework picker** in the header to read the matching product overview: [TypeScript](#what-is-adaptable-for-ag-grid), [React](#what-is-adaptable-for-ag-grid-react), [Angular](#what-is-adaptable-for-ag-grid-angular), or [Vue](#what-is-adaptable-for-ag-grid-vue)
- Learn how to build [Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md): Toolbars, Tool Panels, Settings Panels, Menu Items & Windows etc
#### Can I run multiple AdapTables on the same page?
Yes — AdapTable is designed to support multiple instances on a single page, a common pattern in dashboards, trading blotters and multi-grid analytics applications.
Each instance is identified by its [AdaptableId](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md), which keeps the state, configuration and Team Sharing data of each grid fully separate.
Each AdapTable instance is fully independent — they can use different themes, layouts and even different row models on the same page
#### Where does AdapTable run?
AdapTable is guaranteed to work in Chromium browsers (e.g. Chrome, Edge, Opera etc.)
We aim, but do not guarantee, to keep AdapTable compatible with other leading browsers like Firefox and Safari
AdapTable does not support Internet Explorer
AdapTable also works inside Electron and other Chromium-based frameworks.
AdapTable is fully compatible with [OpenFin](https://openfin.co/) and [interop.io](https://interop.io/) (and includes extra, bespoke functionality when running in either of those containers).
See [OpenFin Plugin](https://www.adaptabletools.com/docs/integrations-openfin/index.md) and [interop.io Plugin](https://www.adaptabletools.com/docs/integrations-interop/index.md) for details of integration with these 2 partners
## AG Grid & Data
#### Which row models are supported?
AG Grid provides 4 different 'Row Models' for different use cases, 3 of which are supported by AdapTable:
A Row Model is essentially a mechanism for loading data into AG Grid
| Name | Description | Server Based | AdapTable Support |
| ----------- | ------------------------------------------------ | :----------: | :---------------: |
| Client Side | All data loaded into grid, all actions on client | ❌ | ✅ |
| Server side | Supports lazy loading, including groups & aggs | ✅ | ✅ |
| Viewport | Loads data only for rows currently visible | ✅ | ✅ |
| Infinite | Loads Data as User Scrolls | ✅ | ❌ |
The Client-Side Row Model is the default - both for AdapTable and AG Grid - and is the most feature rich, allowing users to access advanced Querying and Filtering functionality straight out of the box.
All the demos in this documentation use the Client Side Row Model.
- Use the Client Side Row Model wherever possible: it requires the least additional work and is the most dependable
- Only use a different Row Model if you have proven that loading all the data up front is insufficient for your needs
AdapTable also works fully with the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) and provides additional support and assistance for external filtering and querying (since these are not available natively).
- AdapTable extends AG Grid Enterprise so does not officially support the Infinite Row Model
- But it does fully support the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) - which extends it - as well as the [ViewPort Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-viewport/index.md)
#### Does AdapTable handle live and streaming data?
Yes — AdapTable was built with high-throughput, ticking data in mind and is widely used in financial trading applications where rows update many times per second.
When data changes:
- [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md), [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [Filters](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) re-evaluate in real time
- [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) draw attention to changes
- [Reactive Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) watch values and react as they change
AdapTable adds no measurable overhead to AG Grid; your grid remains as fast as it would be without AdapTable
#### How does AdapTable work with AG Grid?
AdapTable **extends** AG Grid.
This means AdapTable doesn't hide AG Grid in any way.
Everything available in AG Grid works fully in AdapTable, and developers still have full access to the full AG Grid Api and can code against it just as if AdapTable was not being used.
- AdapTable will typically add extra features to AG Grid functionality (e.g. for [Master Detail](https://www.adaptabletools.com/docs/handbook-master-detail/index.md) or [Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md))
- But sometimes (as in [Tree Data](https://www.adaptabletools.com/docs/handbook-tree-data-grid/index.md)) AdapTable merely supports what AG Grid provides
AdapTable always supports the most recent major version of AG Grid.
See the [Release Schedule](https://www.adaptabletools.com/support/release-schedule) for a table showing which AG Grid version is supported in each AdapTable version
#### Which version of AG Grid is required?
The current major version — [AdapTable 23](https://www.adaptabletools.com/support/version-230-release-note) — extends AG Grid v.35.3.0.
See the [Release Schedule](https://www.adaptabletools.com/support/release-schedule) for the full version-compatibility table
## Configuration & State
#### Does AdapTable have server components?
No, AdapTable runs purely in your client and has no server.
However it [contains many features](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) that help you perform searching & filtering on the server rather than client.
#### How is user configuration saved?
Every customisation a user makes — Layouts, Filters, Styled Columns, Themes, Dashboard arrangement and dozens of other settings — is collected into a single [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) object.
By default this state is persisted to local storage, so you find the grid exactly as you left it next time you open it.
For production deployments, AdapTable provides full hooks for [Custom State Persistence](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md) so you can **save state remotely** e.g. to your own database, REST endpoint or cloud store (a working Supabase example is included).
Provide [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) to ship Layouts, Filters and Styles with your app before any user customisation is applied
#### Can users share their configuration with the team?
Yes — [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md) lets users publish their configurations (Layouts, Filters, Styled Columns, Alerts, etc.) for colleagues to import directly into their own grid.
Team Sharing runs in one of two modes:
- [Active](https://www.adaptabletools.com/docs/handbook-team-sharing-active/index.md) — users push and pull configurations on demand
- [Referenced](https://www.adaptabletools.com/docs/handbook-team-sharing-referenced/index.md) — shared objects are linked and update automatically when the source changes
Combine Team Sharing with [Permissions](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) to allow only senior users to publish configurations to the rest of the team
#### Can we personalise AdapTable?
Yes, AdapTable is designed to be fully configurable and extensible.
Some of the many "personalisation" options include:
- [Theming](https://www.adaptabletools.com/docs/handbook-theming/index.md) AdapTable to match your colour scheme
- Providing custom [Dashboard Toolbars](https://www.adaptabletools.com/docs/ui-dashboard-custom-toolbars/index.md), [Tool Panels](https://www.adaptabletools.com/docs/ui-tool-panel-custom-tool-panel/index.md) and [Settings Panels](https://www.adaptabletools.com/docs/ui-settings-panel-configuring/index.md#custom-settings-panels)
- Adding an [Application Icon](https://www.adaptabletools.com/docs/ui-tutorial-creating-icon/index.md#application-icon)
## Development
#### Can AdapTable be tested?
Yes, AdapTable is full testable and works with all testing libraries, e.g. Jest, Playwright, Vitest etc
See the [Developer Guide to Testing AdapTable](https://www.adaptabletools.com/docs/dev-guide-support-testing/index.md) for full instructions
#### What is AdapTable written in?
AdapTable is written in [TypeScript](https://www.typescriptlang.org/) (version 5.5.4) and uses React internally.
You do **not need** to use TypeScript to access AdapTable, but if you do, make sure to use version 5.5.4 or higher
The **minimum** required version of React is **18**; avoid using imports / libraries which require a lower version of React
#### Which English variant is used?
AdapTable is written in British English.
- This can be changed to [American English](https://www.adaptabletools.com/docs/ui-tutorial-american-english/index.md) if required
- Full internationalisation is high on [our Road Map](https://www.adaptabletools.com/support/release-road-map) and coming very soon
#### How can I see logging messages from AdapTable?
AdapTable ensures that all critical messages are always visible in the console.
Other messages are only visible if you turn logging on.
See [Logging](https://www.adaptabletools.com/docs/dev-guide-support-logging/index.md) for full instructions on configuring AdapTable's log levels
## Licensing & Releases
#### How is AdapTable licensed?
AdapTable is licensed on an **application** basis — a single licence covers any number of developers, end users and deployments for a given application.
Two licence types are available:
- **Single Application** — for use in one named application
- **Multiple Application** — for use in unlimited applications
See [AdapTable Licenses](https://www.adaptabletools.com/buy/buying-adaptable-licensing) for licence options, pricing and how to request a quote
AdapTable extends AG Grid Enterprise — you will also need a separate [AG Grid Enterprise licence](https://www.ag-grid.com/license-pricing.php)
#### Is AdapTable open source?
No — AdapTable is a commercial product.
You can [evaluate AdapTable](https://www.adaptabletools.com/buy/buying-adaptable-licensing) before purchasing, and the team is happy to provide trial licences for evaluation projects.
All code used in this documentation's demos is freely available to copy, fork and use in your own applications
#### How is AdapTable supported?
The best way to access AdapTable Support is by [raising a Zendesk Support Ticket](https://www.adaptabletools.com/support/adaptable-support-ticket).
See the [Support Guide](https://www.adaptabletools.com/support) for full instructions on how to raise tickets and provide examples
#### When is AdapTable updated?
AdapTable release [regular new versions](https://www.adaptabletools.com/support/release-notes) containing enhancements, new features and bug fixes.
There are a **minimum** of 6 Releases a year (2 of which are guaranteed to be major), but in reality there are many more.
## Other Products
#### Are there other AdapTable products?
AdapTable for Infinite Table will be officially released in January 2027.
This contains a very similar feature-set to AdapTable for AG Grid and extends [Infinite Table for React](https://infinite-table.com/).
## Where do I go next?
| Topic | Description |
| ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [Installation & Integration](https://www.adaptabletools.com/docs/getting-started-installation/index.md) | Install AdapTable and wire it up to your AG Grid instance |
| [Key Concepts](https://www.adaptabletools.com/docs/getting-started-key-concepts/index.md) | Understand the core building blocks used throughout AdapTable |
| [Demos](https://www.adaptabletools.com/docs/documentation-demo-list/index.md) | See AdapTable's features running live — and fork the code |
| [UI Guides & Tutorials](https://www.adaptabletools.com/docs/ui-tutorial-overview/index.md) | Build custom Toolbars, Tool Panels, Settings Panels, Menu Items and Windows |
| [Developer Tutorials](https://www.adaptabletools.com/docs/dev-guide-tutorial-overview/index.md) | Step-by-step guides for the most common integration tasks |
| [AdapTable Query Language](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) | Master AdapTableQL — the engine behind Filters, Alerts and Calculated Columns |
| [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) | Full reference for every configurable option |
| [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) | Drive AdapTable programmatically from your application code |
| [Latest Release Notes](https://www.adaptabletools.com/support/release-notes) | What's new in the current major version |
### React
### Angular
### Vue
---
# Help Page Not Found
Canonical page: https://www.adaptabletools.com/docs/404
> This AdapTable Help Page cannot be found.
>
> Please check back later or [contact AdapTable Support](mailto:support@adaptabletools.com).
---
# /docs/aaaaa
Canonical page: https://www.adaptabletools.com/docs/aaaaa
aaaaaaaaaaaaaaaa
qqqqq
quick links
## Getting Started
Whats New
[Whats New](https://www.adaptabletools.com/docs/getting-started-whats-new/index.md)
Features
[Features](https://www.adaptabletools.com/docs/getting-started-features-guide/index.md)
Showcase Demos
[Showcase Demos](https://www.adaptabletools.com/docs/showcase-demos-overview/index.md)
Installation
[Installation](https://www.adaptabletools.com/docs/getting-started-installation/index.md)
- CommonJS
[CommonJS Installation](https://www.adaptabletools.com/docs/getting-started-installation/index.md#esm-and-cjs-formats)
Integration
[Integration](https://www.adaptabletools.com/docs/getting-started-integration/index.md)
Adaptable and AG Grid Containers
[AdapTable and AG Grid Containers](https://www.adaptabletools.com/docs/getting-started-setting-adaptable-aggrid-containers/index.md)
## Handbook
AdapTable 21.120
Searching / Quick Search
[Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md)
- Configuring Search
[Configuring Search](https://www.adaptabletools.com/docs/handbook-quick-search-configuring/index.md)
- Quick Search as Filter
[Quick Search as Filter](https://www.adaptabletools.com/docs/handbook-quick-search-as-filter/index.md)
Grid Filter
[Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md)
Configuring Grid Filters
[Configuring Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter-configuring/index.md)
- Grid Filter Technical Reference
[Grid Filter Technical Reference](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md)
Named Queries
[Named Queries](https://www.adaptabletools.com/docs/handbook-named-queries/index.md)
- Named Query Technical Reference
[Named Query Technical Reference](https://www.adaptabletools.com/docs/handbook-named-query-technical-reference/index.md)
Notes
[Notes](https://www.adaptabletools.com/docs/handbook-notes/index.md)
- Notes Technical Reference
[Notes Technical Reference](https://www.adaptabletools.com/docs/handbook-notes-technical-reference/index.md)
Comments
[Comments](https://www.adaptabletools.com/docs/handbook-comments/index.md)
- Comments Technical Reference
[Comments Technical Reference](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md)
FreeText Column
[FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md)
- Configuring FreeText Column
[Configuring FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column-configuring/index.md)
Column Filtering
[Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md)
- Custom Filters
- [Custom Filters](https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters/index.md)
- Filter Components
[Filter Components](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md)
- In Filter
[In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md)
- Manually Applying Filters
[Manually Applying Filters](https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying/index.md)
- Configuring Filters
[Configuring Filters](https://www.adaptabletools.com/docs/handbook-column-filter-configuring/index.md)
Column Filter Technical Reference
[Column Filter Technical Reference](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
Alerting
[Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md)
- Data Change Alerts
[Data Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md)
- Relative Change Alerts
[Relative Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-relative-change/index.md)
- Row Change Alerts
[Row Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md)
- Aggregation Alerts
[Aggregation Alerts](https://www.adaptabletools.com/docs/handbook-alerting-aggregation/index.md)
- Observable Alerts
[Observable Alerts](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md)
- Validation Alerts
[Validation Alerts](https://www.adaptabletools.com/docs/handbook-alerting-validation/index.md)
- Reminder Alerts
[Reminder Alerts](https://www.adaptabletools.com/docs/handbook-alerting-schedule/index.md)
- Alert Notification
[Alert Notification](https://www.adaptabletools.com/docs/handbook-alerting-notifications/index.md)
- Alert Message
[Alert Message](https://www.adaptabletools.com/docs/handbook-alerting-message/index.md)
- Alert Behaviours
[Alert Behaviours](https://www.adaptabletools.com/docs/handbook-alerting-behaviours/index.md)
Cell Flashing
[Flashing](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md)
- Row Flashing
[Flashing Rows](https://www.adaptabletools.com/docs/handbook-flashing-row/index.md)
- Configuring Flashing
[Configuring Flashing](https://www.adaptabletools.com/docs/handbook-flashing-cell-configuring/index.md)
- Accessing Flashing
[Accessing Flashing](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
System Status Messages
[System Status Messages](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md)
Toast Notifications
[Toast Notifications](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
Custom Colour Palette
[Custom Colour Palette](https://www.adaptabletools.com/docs/ui-tutorial-custom-colour-palette/index.md)
Custom Sorting
[Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md)
Column Formatting Format Column
[Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md)
- Column Formatting Style
[Column Formatting Style](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md)
- Column Formatting Display Format
[Column Formatting Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md)
String Display Format
[String Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-string/index.md)
Number Display Format
[Number Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md)
Date Display Format
[Date Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-date/index.md)
Template Display Format
[Template Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-template/index.md)
Custom Display Format
[Custom Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-custom/index.md)
- Configuring Column Formatting
[Configuring Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting-configuring/index.md)
- Column Formatting Conditions
[Column Formatting Conditions](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md)
Styled Columns
[Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md)
- Gradient Style
[Gradient Style](https://www.adaptabletools.com/docs/handbook-styled-column-gradient/index.md)
- Percent Bar Style
[Percent Bar Style](https://www.adaptabletools.com/docs/handbook-styled-column-percent-bar/index.md)
- Badge Style
[Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md)
- Sparkline Column
[Sparkline Column](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md)
- Bullet Chart Style
[Bullet Chart Style](https://www.adaptabletools.com/docs/handbook-styled-column-bullet/index.md)
- Rating Style
[Rating Style](https://www.adaptabletools.com/docs/handbook-styled-column-rating/index.md)
- Icon Style
[Icon Style](https://www.adaptabletools.com/docs/handbook-styled-column-icon/index.md)
- Range Bar Style
[Range Bar Style](https://www.adaptabletools.com/docs/handbook-styled-column-range-bar/index.md)
Editing
[Editing](https://www.adaptabletools.com/docs/handbook-editing/index.md)
- SmartEdit
[Smart Edit](https://www.adaptabletools.com/docs/handbook-editing-smart-edit/index.md)
- BulkUpdate
[Bulk Update](https://www.adaptabletools.com/docs/handbook-editing-bulk-update/index.md)
- Shortcut
[Shortcuts](https://www.adaptabletools.com/docs/handbook-editing-shortcut/index.md)
- PlusMinus
[Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md)
- Styling Editable Cells
[Styling Editable Cells](https://www.adaptabletools.com/docs/ui-tutorial-editable-styles/index.md)
- Custom Column Values when Editing
[Providing Custom Column Values when Editing](https://www.adaptabletools.com/docs/handbook-editing-custom-column-values/index.md)
- Editable Cells
[Editable Cells](https://www.adaptabletools.com/docs/handbook-validating-pre-edit/index.md)
- Data Validation
[Data Validation](https://www.adaptabletools.com/docs/handbook-validating/index.md)
- Data Change History
[Data Change History](https://www.adaptabletools.com/docs/handbook-monitoring-data-change-history/index.md)
Calculated Column
[Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md)
- Aggregated Calculated Column
[Aggregated Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column-aggregated/index.md)
- Cumulative Calculated Column
[Cumulative Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column-cumulative/index.md)
- Quantile Calculated Column
[Quantile Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column-quantile/index.md)
- Referencing Calculated Columns
[Referencing Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column-referencing/index.md)
- Technical Reference
[Calculated Column Technical Reference](https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference/index.md)
Theming
[Theme](https://www.adaptabletools.com/docs/handbook-theming/index.md)
- Customising AdapTable Themes
[Customising AdapTable Themes](https://www.adaptabletools.com/docs/handbook-theming-custom/index.md)
- AG Grid Themes
[AG Grid Themes](https://www.adaptabletools.com/docs/handbook-theming-aggrid/index.md)
Notfications
[Notfications](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
Using Notfications
[Using Notfications](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications-using)
Configuring Notfications
[Configuring Notfications](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications-configuring)
Layouts
[Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)
Table Layouts
[Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md)
Pivot Layouts
[Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md)
- Pivot Result Columns
[Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-result-columns/index.md)
- Pivot Total Columns
[Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md)
- Updating Layouts
- [Updating Layouts](https://www.adaptabletools.com/docs/handbook-layouts-updating/index.md)
- Extending Layouts
- [Extending Layouts](https://www.adaptabletools.com/docs/handbook-layouts-extending/index.md)
- Sychnronising Layouts
- [Sychnronising Layouts](https://www.adaptabletools.com/docs/handbook-layouts-synchronising/index.md)
- Table Layout Wizard
[Table Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md)
- Saving Layouts
- [Saving Layouts](https://www.adaptabletools.com/docs/handbook-layouts-saving/index.md)
- Updating Layouts
- [Updating Layouts](https://www.adaptabletools.com/docs/handbook-layouts-updating/index.md)
Column Sizing
[Column Sizing](https://www.adaptabletools.com/docs/handbook-layouts-table-column-sizing/index.md)
Column Pinning
[Column Pinning](https://www.adaptabletools.com/docs/handbook-layouts-table-pinning/index.md)
Row Selection
[Row Selection](https://www.adaptabletools.com/docs/handbook-layouts-table-row-selection/index.md)
Import
[Data Import](https://www.adaptabletools.com/docs/handbook-importing/index.md)
- Configuring Data Import
[Configuring Data Import](https://www.adaptabletools.com/docs/handbook-importing-configuring/index.md)
- Import Technical Reference
[Data Import Technical Reference](https://www.adaptabletools.com/docs/handbook-importing-technical-reference/index.md)
Export
[Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md)
- Export Destinations
[Export Destinations](https://www.adaptabletools.com/docs/handbook-exporting-destinations/index.md)
- Reports
[Reports](https://www.adaptabletools.com/docs/handbook-exporting-reports/index.md)
- Custom Reports
[Custom Reports](https://www.adaptabletools.com/docs/handbook-exporting-reports-custom/index.md)
- Report Format Types
[Report Format Types](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md)
- Visual Excel Report Format
[Visual Excel Report Format](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md#visualexcel)
- Formatting Reports
[Formatting Reports](https://www.adaptabletools.com/docs/handbook-exporting-formatting-reports/index.md)
- Processing Reports
[Processing Reports](https://www.adaptabletools.com/docs/handbook-exporting-processing/index.md)
- Scheduling Reports
[Scheduling Reports](https://www.adaptabletools.com/docs/handbook-exporting-scheduling/index.md)
Team Sharing
[Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md)
- Active Team Sharing
[Active Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing-active/index.md)
- Referenced Team Sharing
[Referenced Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing-referenced/index.md)
Row Grouping
[Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md)
Column Grouping
[Column Grouping](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md)
- Aggregation
[Aggregation](https://www.adaptabletools.com/docs/handbook-aggregation/index.md)
- Grand Total Rows
[Grand Total Rows](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md)
- Only Aggregation
[Only Aggregation](https://www.adaptabletools.com/docs/handbook-aggregation-only/index.md)
Entitlements
[Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md)
- Module Entitlements
[Module Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning-modules/index.md)
- Object Entitlements
[Object Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning-objects/index.md)
- Default Entitlement
[Default Entitlement](https://www.adaptabletools.com/docs/handbook-permissioning-default-access-level/index.md)
Summary
[Summaries](https://www.adaptabletools.com/docs/handbook-summarising/index.md)
- Cell Summary
[Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising-cells/index.md)
- Row Summary
[Row Summary](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md)
Grid Selection
[Grid Selection](https://www.adaptabletools.com/docs/handbook-selecting/index.md)
Highlighting
[Highlighting](https://www.adaptabletools.com/docs/handbook-highlighting-jumping/index.md)
Charts
[Charts](https://www.adaptabletools.com/docs/handbook-charts/index.md)
- Configuring Charts
[Configuring Charts](https://www.adaptabletools.com/docs/handbook-charts-configuring/index.md)
- External Charts
[External Chart Libraries](https://www.adaptabletools.com/docs/handbook-charts-external/index.md)
Data Sets
[DataSet](https://www.adaptabletools.com/docs/handbook-data-sets/index.md)
FDC3
[Using FDC3](https://www.adaptabletools.com/docs/handbook-fdc3/index.md)
- FDC3 Context
[FDC3 Contexts](https://www.adaptabletools.com/docs/handbook-fdc3-context/index.md)
- FDC3 Intents
[FDC3 Intents](https://www.adaptabletools.com/docs/handbook-fdc3-intents/index.md)
- FDC3 Data Mappings
[FDC3 Data Mappings](https://www.adaptabletools.com/docs/handbook-fdc3-mappings/index.md)
- FDC3 Action Column
[FDC3 Action Columns and Buttons](https://www.adaptabletools.com/docs/handbook-fdc3-ui-components/index.md)
- Custom FDC3
[Custom FDC3](https://www.adaptabletools.com/docs/handbook-fdc3-custom/index.md)
- FDC3 Demo App
[FDC3 Demo App](https://www.adaptabletools.com/docs/handbook-fdc3-example/index.md)
-FDC3 Technical Reference
[FDC3 Technical Reference](https://www.adaptabletools.com/docs/handbook-fdc3-technical-reference/index.md)
No Code
[AdapTable No Code](https://www.adaptabletools.com/docs/handbook-no-code/index.md)
- Configuring No Code
[Configuring AdapTable No Code](https://www.adaptabletools.com/docs/handbook-no-code-configuring/index.md)
Master Detail
[Master Detail](https://www.adaptabletools.com/docs/handbook-master-detail/index.md)
Tree Data
[Tree Data](https://www.adaptabletools.com/docs/handbook-tree-data-grid/index.md)
## UI
Dashboard
[Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md)
- Modes
[Dashboard Modes](https://www.adaptabletools.com/docs/ui-dashboard-modes/index.md)
- Tabs and Toolbars
[Toolbars](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md)
- Custom Toolbars
[Custom Toolbars](https://www.adaptabletools.com/docs/ui-dashboard-custom-toolbars/index.md)
- Dashboard Buttons
[Dashboard Buttons](https://www.adaptabletools.com/docs/ui-dashboard-buttons/index.md)
- Dashboard Configuring
[Configuring the Dashboard](https://www.adaptabletools.com/docs/ui-dashboard-configuring/index.md)
ToolPanel
[Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md)
- Module Tool Panels
[Module Tool Panels](https://www.adaptabletools.com/docs/ui-tool-panel-module-tool-panels/index.md)
- Custom Tool Panels
[Custom Tool Panels](https://www.adaptabletools.com/docs/ui-tool-panel-custom-tool-panel/index.md)
- Tool Panel Buttons
[Tool Panel Buttons](https://www.adaptabletools.com/docs/ui-tool-panel-buttons/index.md)
Settings Panel
[Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md)
Custom Settings Panel
[Custom Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel-configuring/index.md#custom-settings-panels)
Wizards
[Wizards](https://www.adaptabletools.com/docs/ui-settings-panel-wizards/index.md)
Status Bar
[AdapTable Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md)
Configuring Status Bar
[Configuring Status Bar](https://www.adaptabletools.com/docs/ui-status-bar-configuring/index.md)
Action Column
[Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md)
Action Column Commands
[Action Column Commands](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md)
Configuring Action Column
[Configuring Action Column](https://www.adaptabletools.com/docs/handbook-action-column-configuring/index.md)
Row Form
[Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md)
Configuring Row Forms
[Configuring Row Forms](https://www.adaptabletools.com/docs/handbook-row-form-configuring/index.md)
Column Menu
[Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md)
- Column Menu Technical Reference
[Column Menu Technical Reference](https://www.adaptabletools.com/docs/ui-column-menu-technical-reference/index.md)
Context Menu
[Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md)
- Configuring Context Menu
[Configuring Context Menu](https://www.adaptabletools.com/docs/ui-context-menu-configuring/index.md)
- Custom Context Menu Items
[Custom Context Menu Items](https://www.adaptabletools.com/docs/ui-context-menu-custom-items/index.md)
- Context Menu Technical Reference
[Context Menu Technical Reference](https://www.adaptabletools.com/docs/ui-context-menu-technical-reference/index.md)
Query Builder
[Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md)
Expression Editor
[Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md)
Functions Dropdown
[Functions Dropdown](https://www.adaptabletools.com/docs/ui-expression-editor/index.md#functions-dropdown)
## Dev Guide
Adaptable State
[Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md)
Custom Adaptable State
[Custom Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-custom/index.md)
Adaptable State Changed
[Adaptable State Changed](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md)
Migrating Adaptable State
[Migrating Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-migrating-state/index.md)
### Adaptable In Depth
Adaptable Object
[Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects)
- suspending Objectg
[Suspending Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#suspending-objects)
Adaptable Column
[Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md)
Adaptable Button
[Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md)
Adaptable Icon
[Adaptable Icon](https://www.adaptabletools.com/docs/ui-tutorial-creating-icon/index.md)
Adaptable Form
[Adaptable Forms](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md)
Adaptable Style
[Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md)
Scope
[Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md)
Select Editor
[Select Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md)
Numeric Cell Editor
[Numeric Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-numeric/index.md)
Percentage Cell Editor
[Percentage Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-percentage/index.md)
Date Picker
[Date Picker](https://www.adaptabletools.com/docs/handbook-cell-editors-date-picker/index.md)
### Tutorials
Primary Key
[Primary Key](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md)
Setting the Adaptable Id
[Setting the Adaptable Id](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md)
Providing User Name
[User Name](https://www.adaptabletools.com/docs/getting-started-user-name/index.md)
Adaptable Context
[Adaptable Context](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context/index.md)
Setting the Adaptable State Key
[Adaptable State Key](https://www.adaptabletools.com/docs/getting-started-adaptable-state-key/index.md)
Adaptable License Key
[License Key](https://www.adaptabletools.com/docs/getting-started-license-key/index.md)
Adaptable State
[Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md)
State Management
[State Management](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-management/index.md)
Column Types
[Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md)
Cell Data Types
[Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md)
Hiding Columns
[Hiding Columns](https://www.adaptabletools.com/docs/dev-guide-columns-hiding-columns/index.md)
Adaptable Context
[Adaptable Context](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context/index.md)
Holiday Calendars
[Adding Holiday Calendars](https://www.adaptabletools.com/docs/dev-guide-tutorial-holiday-calendars/index.md)
Configuring Column Headers
[Configuring Column Headers](https://www.adaptabletools.com/docs/dev-guide-columns-column-headers/index.md)
Setting Cell Editability
[Setting Cell Editability](https://www.adaptabletools.com/docs/dev-guide-tutorial-setting-cell-editability/index.md)
Loading Grid Data
[Loading Grid Data](https://www.adaptabletools.com/docs/handbook-managing-grid-data-loading/index.md)
Managing Grid Rows
[Managing Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-transaction/index.md)
Adding Grid Rows
[Adding Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-add/index.md)
Updating Grid Rows
[Updating Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-update/index.md)
Updating Cells
[Updating Grid Cells](https://www.adaptabletools.com/docs/handbook-managing-grid-data-cells/index.md)
Deleting Grid Rows
[Deleting Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-delete/index.md)
Logging
[Logging](https://www.adaptabletools.com/docs/dev-guide-support-logging/index.md)
Testing AdapTable
[Testing AdapTable](https://www.adaptabletools.com/docs/dev-guide-support-testing/index.md)
AG Grid Cell Rendering
[AG Grid Cell Rendering](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-rendering/index.md)
Monitoring Column Info
[Monitoring Column Info](https://www.adaptabletools.com/docs/dev-guide-columns-column-info/index.md)
Monitoring Grid Info
[Monitoring Grid Info](https://www.adaptabletools.com/docs/dev-guide-support-monitoring/index.md)
Transposing the Grid
[Transposing the Grid](https://www.adaptabletools.com/docs/handbook-transposing/index.md)
Displaying a Progress Indicator
[Displaying a Progress Indicator](https://www.adaptabletools.com/docs/ui-progress-indicator/index.md)
Showing a Custom Popup
[Showing a Custom Popup](https://www.adaptabletools.com/docs/ui-popup-windows/index.md#custom-window)
Configuring the Loading Screen
[Configuring the Loading Screen](https://www.adaptabletools.com/docs/ui-loading-screen/index.md)
### Row Models
Server-Side Row Model
[Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md)
Viewport Row Model
[Viewport Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-viewport/index.md)
### Custom Content
Custom Expression Function
[Custom Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md)
Standard Custom Expression Function
[Standard Custom Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-standard/index.md)
Aggregated Custom Expression Function
[Aggregation Custom Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-aggregation/index.md)
Custom Expression Function Scope
[Custom Expression Function Scope](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom-scope/index.md)
Adaptable Performance
[Adaptable Performance](https://www.adaptabletools.com/docs/dev-guide-support-adaptable-performance/index.md)
Weighted Average
[Creating Weighted Averages](https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average/index.md)
## Predicates
Adaptable Predicates
[Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md)
- System Predicates
[System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md)
- Custom Predicates
[Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md)
### Adaptable QL
Adaptable Ql Overview
[AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)
Adaptable Expression
[Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)
- QUERY Expression
[QUERY Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-query-function/index.md)
- VAR Expression
[VAR Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-var-function/index.md)
- Row Data
[Expression Row Data](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-row-data/index.md)
- Logic
[Logic Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md)
- Advanced Expressions
[Advanced Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced/index.md)
- Standard Expression
[Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md)
- Reactive Expressions
[Adaptable Rx](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md#reactive-expressions)
- Observable Expression
[Observable Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md)
- Aggregation Expressions
[Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md)
- AdapTableQL Expression Functions
[AdapTableQL Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md)
Reducing Expression Complexity
[Reducing Expression Complexity](https://www.adaptabletools.com/docs/adaptable-ql-expression-managing/index.md)
Server Evaluation
[Server Evaluation](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md)
## Reference
### Adaptable Options
Adaptable Options Overview
[Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md)
Base Adaptable Options
[Base Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md)
Expression Options
[Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md)
Action Column Options
[Action Column Options](https://www.adaptabletools.com/docs/handbook-action-column-technical-reference/index.md)
Row Form Options
[Row Form Options](https://www.adaptabletools.com/docs/handbook-row-form-technical-reference/index.md)
Alert Options
[Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
Charting Options
[Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md)
Column Options
[Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md)
Container Options
[Container Options](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-containers/index.md)
Data Change History Options
[Data Change History Options](https://www.adaptabletools.com/docs/handbook-monitoring-data-change-history-technical-reference/index.md)
Data Set Options
[Data Set Options](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md)
Dashboard Options
[Dashboard Options](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md)
Edit Options
[Edit Options](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md)
Entitlement Options
[Entitlement Options](https://www.adaptabletools.com/docs/handbook-permissioning-technical-reference/index.md)
Export Options
[Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md)
Export Initial State
[Export Initial State](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md)
Column Filter Options
[Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
Cell Summary Options
[Cell Summary Options](https://www.adaptabletools.com/docs/handbook-summarising-technical-reference/index.md)
Custom Sort Options
[Custom Sort Options](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md)
Grid Filter Options
[Grid Filter Options](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md)
Flashing Cell Options
[Flashing Cell Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Format Column Options
[Format Column Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Layout Options
[Layout Options](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md)
Column Menu Options
[Column Menu Options](https://www.adaptabletools.com/docs/ui-column-menu-technical-reference/index.md)
Context Menu Options
[Context Menu Options](https://www.adaptabletools.com/docs/ui-context-menu-technical-reference/index.md)
Notification Options
[Notification Options](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
Expression Options
[Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md)
Quick Search Options
[Quick Search Options](https://www.adaptabletools.com/docs/handbook-quick-search-technical-reference/index.md)
Settings Panel Options
[Settings Panel Options](https://www.adaptabletools.com/docs/ui-settings-panel-technical-reference/index.md)
State Options
[State Options](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md)
Team Sharing Options
[Team Sharing Options](https://www.adaptabletools.com/docs/handbook-team-sharing-technical-reference/index.md)
Tool Panel Options
[Tool Panel Options](https://www.adaptabletools.com/docs/ui-tool-panel-technical-reference/index.md)
User Interface Options
[User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md)
### Initial State
Initial State
[Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md)
Alert Initial State
[Alert Initial State](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
Charting Initial State
[Charting Initial State](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md)
Custom Sort State
[Custom Sort Initial State](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md)
Dashboard Initial State
[Dashboard Initial State](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md)
Flashing Cell
[Flashing Cell Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Format Column Initial State
[Format Column Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
FreeText Column Initial State
[FreeText Column Initial State](https://www.adaptabletools.com/docs/handbook-freetext-column-technical-reference/index.md)
Layout Initial State
[Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md)
Status Bar Initial State
[Status Bar Initial State](https://www.adaptabletools.com/docs/ui-status-bar-technical-reference/index.md)
Quick Search Initial State
[Quick Search Initial State](https://www.adaptabletools.com/docs/handbook-quick-search-technical-reference/index.md)
Styled Column Initial State
[Styled Column Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Theme Initial State
[Theme Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Tool Panel Initial State
[Tool Panel Initial State](https://www.adaptabletools.com/docs/ui-tool-panel-technical-reference/index.md)
### Adaptable API
Adaptable API Overview
[Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md)
Alert API
[Alert API](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
Charting API
[Charting API](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md)
Column API
[Column API](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md)
State API
[State API](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md)
Custom Sort API
[Custom Sort API](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md)
Dashboard API
[Dashboard API](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md)
DataSet API
[DataSet API](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md)
Filter API
[Filter API](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
Flashing Cell API
[Flashing Cell API](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Format Column API
[Format Column API](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
Grid API
[Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)
Layout API
[Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md)
Options API
[Options API](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md)
Query API
[Query API](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md)
Quick Search API
[Quick Search API](https://www.adaptabletools.com/docs/handbook-quick-search-technical-reference/index.md)
Row Form API
[Row Form API](https://www.adaptabletools.com/docs/handbook-row-form-technical-reference/index.md)
Scope API
[Scope API](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md)
Settings Panel API
[Settings Panel API](https://www.adaptabletools.com/docs/ui-settings-panel-technical-reference/index.md)
Styled Column API
[Styled Column API](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
System Status API
[System Status API](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
Team Sharing API
[Team Sharing API](https://www.adaptabletools.com/docs/handbook-team-sharing-technical-reference/index.md)
Tool Panel API
[Tool Panel API](https://www.adaptabletools.com/docs/ui-technical-reference/index.md)
### Events
Events Overview
[Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md)
Adaptable Ready Event
[Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md)
Row Form Submitted Event
[Row Form Submitted Event](https://www.adaptabletools.com/docs/handbook-row-form-technical-reference/index.md)
Alert Fired Event
[Alert Fired Event](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
Cell Changed Event
[Cell Changed Event](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md)
Layout Changed Event
[Layout Changed Event](https://www.adaptabletools.com/docs/handbook-layouts-monitoring/index.md)
Chart Changed Event
[Chart Changed Event](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md)
Row Changed Event
[Row Changed Event](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)
Dashboard Changed Event
[Dashboard Changed Event](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md)
Data Set Selected Event
[Data Set Selected Event](https://www.adaptabletools.com/docs/handbook-data-set-technical-reference/index.md)
Custom Toolbar Configured Event
[Custom Toolbar Configured Event](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md)
Filter Applied Event
[Column Filter Applied Event](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
Grid Sorted Event
[Grid Sorted Event](https://www.adaptabletools.com/docs/handbook-custom-sorting-technical-reference/index.md)
Selection Changed Event
[Selection Changed Event](https://www.adaptabletools.com/docs/handbook-selecting-changed-event/index.md)
Adaptable State Changed Event
[Adaptable State Changed Event](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md)
Live Data Changed Event
[Live Data Changed Event](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md)
Theme Changed Event
[Theme Changed Event](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
System Status Message Displayed Event
[System Status Message Displayed Event](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
Custom ToolPanels (Tool Panel Options)
[Custom ToolPanels](https://www.adaptabletools.com/docs/ui-tool-panel-custom-tool-panel/index.md)
### AdapTableQL Reference
Expressions List
[AdapTableQL Expression List](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md)
### Modules
Module Overview
[Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md)
### AG Grid Modules
AG Grid Module Overview
[AG Grid Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md)
## Partner Integrations
OpenFin
[OpenFin](https://www.adaptabletools.com/docs/integrations-openfin/index.md)
ipushpull
[ipushpull](https://www.adaptabletools.com/docs/integrations-ipushpull/index.md)
Interop.io
[interop.io](https://www.adaptabletools.com/docs/integrations-interop/index.md)
## Plugins
Plugins Overview
[Plugins](https://www.adaptabletools.com/docs/technical-reference-plugins/index.md)
ipushpull Plugin
[ipushpull Plugin](https://www.adaptabletools.com/docs/integrations-ipushpull/index.md)
OpenFin Plugin
[OpenFin Plugin](https://www.adaptabletools.com/docs/integrations-openfin/index.md)
No Code Plugin
[No Code Plugin](https://www.adaptabletools.com/docs/handbook-no-code/index.md)
Master Detail Plugin
[Master Detail Plugin](https://www.adaptabletools.com/docs/handbook-master-detail/index.md)
- OpenFin Plugin Options
[OpenFin Plugin Options](https://www.adaptabletools.com/docs/integrations-openfin/index.md)
## Frameworks
AdapTable React
[AdapTable React](https://www.adaptabletools.com/docs/index.md)
AdapTable React Integration
[AdapTable React Integration](https://www.adaptabletools.com/docs/react-integration/index.md)
AdapTable React Installation
[AdapTable React Installation](https://www.adaptabletools.com/docs/react-installation/index.md)
AdapTable React Components
[Building Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md)
AdapTable React Hooks
[AdapTable React Hooks](https://www.adaptabletools.com/docs/react-adaptable-hooks/index.md)
AdapTable Angular
[AdapTable Angular](https://www.adaptabletools.com/docs/index.md)
AdapTable Angular Integration
[AdapTable Angular Integration](https://www.adaptabletools.com/docs/angular-integration/index.md)
AdapTable Angular Installation
[AdapTable Angular Installation](https://www.adaptabletools.com/docs/angular-installation/index.md)
AdapTable Angular Components
[Building Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md)
AdapTable Vue
[AdapTable Vue](https://www.adaptabletools.com/docs/index.md)
AdapTable Vue Integration
[AdapTable Vue Integration](https://www.adaptabletools.com/docs/vue-integration/index.md)
AdapTable Vue Installation
[AdapTable Vue Installation](https://www.adaptabletools.com/docs/vue-installation/index.md)
AdapTable Vue Components
[Building Custom Components](https://www.adaptabletools.com/docs/ui-tutorial-building-custom-components/index.md)
Version 23.0
[Version 23.0 Developer Release Note](https://www.adaptabletools.com/support/version-230-release-note)
Version 22.1
[Version 22.1 Developer Release Note](https://www.adaptabletools.com/support/version-221-release-note)
Version 22.0
[Version 22.0 Developer Release Note](https://www.adaptabletools.com/support/version-220-release-note)
Version 21.1
[Version 21.1 Developer Release Note](https://www.adaptabletools.com/support/version-211-release-note)
Version 21.0
[Version 21.0 Developer Release Note](https://www.adaptabletools.com/support/version-210-release-note)
Version 20.3
[Version 20.3 Developer Release Note](https://www.adaptabletools.com/support/version-203-release-note)
Version 20.2
[Version 20.2 Developer Release Note](https://www.adaptabletools.com/support/version-202-release-note)
Version 20.1
[Version 20.1 Developer Release Note](https://www.adaptabletools.com/support/version-201-release-note)
Version 20.0
[Version 20.0 Developer Release Note](https://www.adaptabletools.com/support/version-200-release-note)
Version 19.2
[Version 19.2 Developer Release Note](https://www.adaptabletools.com/support/version-192-release-note)
Version 19.1
[Version 19.1 Developer Release Note](https://www.adaptabletools.com/support/version-191-release-note)
Version 19.0
[Version 19.0 Developer Release Note](https://www.adaptabletools.com/support/version-190-release-note)
Version 18.1
[Version 18.1 Developer Release Note](https://www.adaptabletools.com/support/version-181-release-note)
Version 18.0
[Version 18.0 Release Note](https://www.adaptabletools.com/support/version-180-release-note)
Version 17
[Version 17 Developer Release Note](https://www.adaptabletools.com/support/version-17-release-note)
Version 16
[Version 16 Developer Release Note](https://www.adaptabletools.com/support/version-16-release-note)
Version 15
[Version 15 Developer Release Note](https://www.adaptabletools.com/support/version-15-release-note)
Version 14
[Version 14 Developer Release Note](https://www.adaptabletools.com/support/version-14-release-note)
Version 13
[Version 13 Developer Release Note](https://www.adaptabletools.com/support/version-13-release-note)
Version 12
[Version 12 Developer Release Note](https://www.adaptabletools.com/support/version-12-release-note)
Version 11
[Version 11 Developer Release Note](https://www.adaptabletools.com/support/version-11-release-note)
Version 10
[Version 10 Developer Release Note](https://www.adaptabletools.com/support/version-10-release-note)
Version 9
[Version 9 Developer Release Notes](https://www.adaptabletools.com/support/version-9-change-log)
Licensing
[Licensing](https://www.adaptabletools.com/buy/buying-adaptable-licensing)
Contact Us
[Contact Us](https://www.adaptabletools.com/buy/buying-adaptable-contact-us)
Privacy Policy
[Privacy Policy](https://www.adaptabletools.com/buy/buying-adaptable-privacy-policy)
Support Tickets
[Support Tickets](https://www.adaptabletools.com/support/adaptable-support-ticket)
Support Commitment
[Support Commitment](https://www.adaptabletools.com/support/adaptable-support-commitment)
Release Schedule
[Release Schedule](https://www.adaptabletools.com/support/release-schedule)
Release Notes
[Release Notes](https://www.adaptabletools.com/support/release-notes)
Previous Versions
[Previous Documentation Versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md)
Demo List
[Demo List](https://www.adaptabletools.com/docs/documentation-demo-list/index.md)
Video List
[Video List](https://www.adaptabletools.com/docs/documentation-video-list/index.md)
Grid Gurus
[Grid Gurus](https://www.adaptabletools.com/buy/buying-adaptable-grid-gurus)
Array Columns
[Array Columns](https://www.adaptabletools.com/docs/dev-guide-aggrid-array-columns/index.md)
---
# AdapTable Predicates
Canonical page: https://www.adaptabletools.com/docs/adaptable-predicate
- An Adaptable Predicate is a boolean function (system or custom) which evaluates to a true / false value
- Designed to be lightweight and easy to use - both in the Adaptable UI and in Initial Adaptable State
- Used primarily in Column Filters but also in Alerts, Badges, Flashing Cells and Conditional Styles
AdapTable Predicates are used for creating, and evaluating, boolean Rules.
- AdapTable also provides [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) which are designed for more complex use cases
- They are an entirely different way to query data in AdapTable and are evaluated using [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)
- You can use either Predicates or Expressions for any given use case, but they cannot be mixed together
- e.g. you cannot include a [Custom Predicate](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) in an Expression, or reference an [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) in a Predicate
## Predicates Overview
A Predicate is a function which always returns a boolean result (e.g. `Positive`, `Today`).
Some Predicates receive an input argument, e.g. `Contains` (number), `After` (date), `Between` (2 numbers)
Predicates are usually evaluated against one or more Columns or DataTypes
AdapTable makes creating Predicates in the UI easy by providing context sensitive dropdows that contain only values relevant to the current use case.
- Predicates required for [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) can be entirely handwritten if that is the preference
- Alternatively, they can be first created in the UI and then the contents copied over into the Initial State file
### Predicate Types
There are 2 types of Predicates:
- [System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md) - shipped by AdapTable and designed to cover most use cases
- [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) - defined by developers in Adaptable Options - used to meet precise user requirements
### Module Scope
Predicates can be used in 5 [Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md) in AdapTable:
We have also noted where [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) can be used as an alternative to Predicates
| Module | No.of Predicates Allowed | Module also uses Expressions |
| ---------------------------------------------------------------------------------- | :----------------------: | :--------------------------: |
| [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) | Multiple | ✅ |
| [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) | One | ❌ |
| [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) | Multiple | ✅ |
| [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) | Multiple | ✅ |
| [Badge Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) | Multiple | ❌ |
### DataType Scope
Each System Predicate is designed to be used by **one Column DataType only** e.g. number, date or text.
There are 4 exceptions: `Blanks`, `NonBlanks`, `In` & `NotIn` which can be applied to **every** DataType
#### Similar Behaviour
For the majority of Predicates the single Data Type Scope rule is not a problem
This is because they are only relevant to a single DataType (e.g. `ThisWeek` has to be a Date).
However, a few Predicate behaviours (e.g. Equals) can be suitable for more than one DataType.
When this happens a **differently and appropriately named** Predicate is provided for each DataType.
Here are some examples of similar behaviours with different Predicates for each Data Type:
| Numeric | Date | String |
| :-----------: | :------: | :----: |
| `Equals` | `On` | `Is` |
| `GreaterThan` | `After` | |
| `LessThan` | `Before` | |
| `Between` | `Range` | |
- The [System Predicates List](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md) provides a full list of System Predicates shipped by AdapTable
- It also includes details of both Module and Column Data Type Scope
## Using Predicates
Predicates are designed to be easy to use both at run-time and design-time.
The [`AdaptablePredicate`](https://www.adaptabletools.com/docs/reference/adaptablepredicate.md) object contains just 2 properties:
| Property | Type | Description |
| --- | --- | --- |
| [Inputs](https://www.adaptabletools.com/docs/reference/adaptablepredicate.md#inputs) | `any[]` | Optional Inputs that might be needed for evaluation |
| [PredicateId](https://www.adaptabletools.com/docs/reference/adaptablepredicate.md#predicateid) | `PREDICATE_TYPE` | Id of Predicate (e.g. `Equals`, `GreaterThan`) |
**Inputs** are used when the Predicate requires extra information for its evaluation; they can receive:
- 0 inputs (e.g. `Blanks`)
- 1 input (e.g. `GreaterThan`)
- 2 inputs (e.g. `Between`)
- array of inputs (**only** used in `In` & `NotIn` in Column Filter Predicates - similar to SQL 'IN')
AdapTable's evaluation for `In` Predicate returns _true_ if the Column contains **any** of the values
### Creating Predicates at RunTime
Predicates are straightforward to use in the AdapTable UI.
AdapTable will provide a list of available Predicates automatically generated according to context.
For example, if the Scope is a number and the Module is Alert, then only numeric Predicates supported by Alerts will be displayed.
AdapTable ensures Custom Predicates are only selectable where their Column or DataType scope allows
Once the Predicate has been selected an input control (or controls) will appear if the Predicate requires inputs.
The control displayed will vary based on the input DataType (e.g. a Date Picker if a date is required)
### Defining Predicates in Initial State
It is straightforward to supply a Predicate in [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md).
The `PredicateId` is always required and `Inputs` should be provided if required by the Predicate for evaluation:
```tsx {18,23,28,33,38,50}
const initialState: InitialState = {
Layout: {
CurrentLayout: 'Table Layout',
Layouts: [
{
Name: 'Table Layout',
TableColumns: [
'OrderId',
'Price',
'Age',
'Currency',
'TradeDate',
],
ColumnFilters: [
{
// Using no inputs
ColumnId: 'Price',
Predicates: [{ PredicateId: 'Positive' }],
},
{
// Using 1 input
ColumnId: 'OrderId',
Predicates: [{ PredicateId: 'GreaterThan', Inputs: [15] }],
},
{
// Using 2 inputs
ColumnId: 'Age',
Predicates: [{ PredicateId: 'Between', Inputs: [18, 65] }],
},
{
// Providing In Predicate as array
ColumnId: 'Currency',
Predicates: [{ PredicateId: 'In', Inputs: ['GBP', 'EUR', 'USD'] }],
},
{
// Using a Custom Predicate
ColumnId: 'TradeDate',
Predicates: [{ PredicateId: 'ThisBusinessYear'] }],
},
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'positive-green',
Scope: { DataTypes: ['number'] },
Style: { ForeColor: 'Green'},
Rule: {
Predicates: [{ PredicateId: 'Positive' } ]
},
},
],
}
};
```
### Accessing Predicates programmatically
The [Predicate API](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md) section of Adaptable API contains a number of functions providing access to Predicates.
---
# Custom Predicates
Canonical page: https://www.adaptabletools.com/docs/adaptable-predicate-custom
- In addition to the [many Predicates shipped by AdapTable](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md), developers can provide their own Predicate Definition
- This is done via the `customPredicateDefs` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md)
- Once created, Custom Predicates are used in exactly the same way as System Predicates
- Each Predicate Definition must:
- include a `handler` function to be invoked by AdapTable
- configure which Modules can use the Predicate
- set which Columns (or DataTypes) can access the Predicate
- Custom Predicates can override existing System Predicates with bespoke behaviour
The [Predicates shipped by AdapTable](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md) can be extended by Custom Predicates provided by developers.
## Custom Predicate Definitions
Custom Predicates are provided in the `customPredicateDefs` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md).
Each is based on a [`Predicate Definition`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md) object.
- Custom Predicates add bespoke items to the [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) available in AdapTable
- Use [Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) to extend Expressions
### `customPredicateDefs`
Definitions for Custom-provided Predicates
[`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)
Custom Predicate Definitions are provided by developers at Design-Time.
These extend the [many Predicates shipped by AdapTable](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md).
The full definition of the [`Predicate Definition`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md) is as follows:
| Property | Type | Description |
| --- | --- | --- |
| [columnScope](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#columnscope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Columns (or DataTypes) where Predicate is active |
| [handler](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#handler) | `(params: `[`PredicateDefHandlerContext`](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md)`) => boolean` | Actual boolean function invoked when evaluating the Predicate |
| [icon](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#icon) | [`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)` \| \{ text: string; \}` | Icon to show (primarily used in Filter dropdown) |
| [id](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#id) | `PREDICATE_TYPE` | Predicate Id |
| [inputs](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#inputs) | [`PredicateDefInput`](https://www.adaptabletools.com/docs/reference/predicatedefinput.md)`[]` | Inputs the Predicate can take |
| [label](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#label) | `string` | Name of the Predicate |
| [moduleScope](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#modulescope) | [`PredicateModuleScope`](https://www.adaptabletools.com/docs/reference/predicatemodulescope.md)`[]` | Modules where Predicate can run |
| [shortcuts](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#shortcuts) | `string[]` | Keyboard shortcuts to initiate predicate - used in Quick Filter bar |
| [toString](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md#tostring) | `(params: `[`PredicateDefToStringParams`](https://www.adaptabletools.com/docs/reference/predicatedeftostringparams.md)`) => string` | String representation of the Predicate |
## Mandatory Properties
The **Predicate Definition** object contains many properties which can be set, of which 5 are mandatory:
### id
The `id` defines how the Predicate is referenced in other objects (e.g. Column Filters)
### label
The `label` is the name given to the Predicate and how it will be referenced in the AdapTable UI.
- The `id` is the unique identifier for the Predicate
- The `label` is a more friendly way of identifying the Predicate in the UI
### handler
The `handler` property is a function which is invoked by AdapTable each time the predicate is evaluated.
The function receives information about the current evaluation context and returns a boolean (true / false).
### Understanding the handler property
The `handler` function is defined as follows:
```js
handler: (context: PredicateDefHandlerContext) => boolean;
```
As can be seen, it receives a [`PredicateDefHandlerContext`](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md) object and returns a boolean.
The `context` contains all the properties required for predicate evaluation (e.g. given cell, node and column).
The full definition is as follows:
| Property | Type | Description |
| --- | --- | --- |
| [column](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#column) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) | AdapTable Column which contains the cell |
| [displayValue](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#displayvalue) | `any` | Display value in cell being evaluated |
| [groupValues](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#groupvalues) | `string[]` | For grouped columns, the array with all the values starting from the root group to the current node |
| [inputs](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#inputs) | `any[]` | Any (optional) inputs required to perform evaluation |
| [node](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#node) | `IRowNode` | AG Grid Row node which contains the cell |
| [oldValue](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#oldvalue) | `any` | Previous value in cell (e.g. if evaluating an edit) |
| [predicatesOperator](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#predicatesoperator) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`['PredicatesOperator']` | Logic used when combining multiple Predicates ('AND'\|'OR') |
| [rawValue](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#rawvalue) | `any` | Raw value in cell being evaluated (as per underlying data source) |
| [treeSelectionState](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#treeselectionstate) | `TreeSelectionState` | Optional TreeSelectionState - used for `In` predicate, when evaluating the grouped column. If this is not provided, another valid implementation is used. |
| [value](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#value) | `any` | Value in cell being evaluated (normalized as per Column DataType) |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/predicatedefhandlercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
### moduleScope
This array property specifies which AdapTable Modules can use the Predicate.
The `moduleScope` property is of type [`PredicateModuleScope`](https://www.adaptabletools.com/docs/reference/predicatemodulescope.md) which can be one, some, or all of:
- `customFilter` - used in [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md)
- `alert` - can trigger an [Alert](https://www.adaptabletools.com/docs/handbook-alerting/index.md)
- `flashingCell` - available in [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md)
- `formatColumn` - used to define a [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md)
- `badgeStyle` - used to define a [Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md)
### columnScope
The `columnScope` property - of type [`Column Scope`](https://www.adaptabletools.com/docs/reference/columnscope.md) - defines **where** the Predicate can be applied.
- For System Predicates the Scope is always of type `DataType`
- For Custom Predicates the Scope can be a DataType, but can also be limited to particular ColumnId(s)
See [the Guide to Scope in AdapTable](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for more information
## Creating Custom Predicates
Now lets put this all together see how to create a Custom Predicate Definition.
### Creating a Custom Predicate Definition
In this guide we will create a Custom Predicate Definition that will check whether a given date is after a fictitious takeover date.
Supply 2 properties to identify the Custom Predicate:
- `id` - the unique identifier for the Predicate
- `label` - how the Predicate will be referenced in the UI
Both these properties are mandatory
```tsx [[1, 5, "id"], [1, 6, "label"]]
const adaptableOptions: AdaptableOptions = {
predicateOptions:{
customPredicateDefs: [
{
id: 'post_takeover',
label: 'Post Takeover',
columnScope: {DataTypes: ['date']},
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return (context.value as Date) > new Date('2019-09-21');
},
toString: () => `> '2019-09-21'`,
},
],
},
};
```
The `columnScope` property defines **where** the Predicate can be applied.
It is of type [Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) used in many places in AdapTable.
You can provide either:
- an array of ColumnIds
- an array of DataTypes (though its likely only one value will be used)
```tsx [[2, 7, "columnScope"]]
const adaptableOptions: AdaptableOptions = {
predicateOptions:{
customPredicateDefs: [
{
id: 'post_takeover',
label: 'Post Takeover',
columnScope: {DataTypes: ['date']},
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return (context.value as Date) > new Date('2019-09-21');
},
toString: () => `> '2019-09-21'`,
},
],
},
};
```
The `moduleScope` property defines **which Modules** in AdapTable can use the Custom Predicate. The value will be one, some, or all of
- `columnFilter` - using the [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md)
- `alert` - see [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md)
- `flashingcell` - see [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md)
- `formatcolumn` - see [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md)
- `badgeStyle` - see [Badge Styles](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md)
```tsx [[3, 8, "moduleScope"]]
const adaptableOptions: AdaptableOptions = {
predicateOptions:{
customPredicateDefs: [
{
id: 'post_takeover',
label: 'Post Takeover',
columnScope: {DataTypes: ['date']},
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return (context.value as Date) > new Date('2019-09-21');
},
toString: ({inputs}) => `> ${inputs[0]}`,
},
],
};
```
The `handler` function will be invoked by AdapTable each time the predicate is evaluated.
This is a **mandatory** property.
`handler` receives a `PredicateDefHandlerContext` object (that contains all the arguments required for evaluation) and returns a boolean.
```tsx [[5,9, "handler"]]
const adaptableOptions: AdaptableOptions = {
predicateOptions:{
customPredicateDefs: [
{
id: 'post_takeover',
label: 'Post Takeover',
columnScope: {DataTypes: ['date']},
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return (context.value as Date) > new Date('2019-09-21');
},
toString: () => `> '2019-09-21'`,
},
],
},
};
```
The `toString` property is a function which defines how AdapTable will describe the predicate in the UI Settings Screen.
It should be succint but as descriptive as required.
It can take an input if required (see step below).
```tsx [[5,12, "toString"]]
const adaptableOptions: AdaptableOptions = {
predicateOptions:{
customPredicateDefs: [
{
id: 'post_takeover',
label: 'Post Takeover',
columnScope: { DataTypes: ['date'] },
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return (context.value as Date) > new Date('2019-09-21');;
},
toString: () => `> '2019-09-21'`,
}],
};
}
```
It is possible that the Custom Predicate might require an [input](#adding-inputs).
When this is the case AdapTable will supply the appropriate editor in the UI (in this case in the Format Column wizard).
Here we have provided a Custom Predicate that works on string columns and is triggered when the cell length is greater than the inputted number.
Note: we have provided this input value to the `toString()` method.
```tsx [[5,12, "inputs"]]
const adaptableOptions: AdaptableOptions = {
predicateOptions: {
customPredicateDefs: [
{
id: 'long_string',
label: 'Long String',
columnScope: {DataTypes: ['text']},
moduleScope: ['formatcolumn'],
handler(context: PredicateDefHandlerContext) {
return (context.value as String).length > context.inputs[0];
},
inputs: [{type: 'number'}],
toString: ({inputs}) => `cell length > ${inputs[0]}`,
},
],
},
};
```
**Example: Custom Predicates**
Adds 3 Custom Predicates
- This demo creates 3 Custom Predicate Definitions, with a variety of different Module and Column Scope:
- `Popular` (Module Scope of `columnFilter`; Column Scope of `name`) - where the Row has many Stars and Watchers
- `Vanilla` (Module Scope of `columnFilter` & `formatColumn`; Column Scope of `language`) - where language is JavaScript or HTML
- `Popular` (Module Scope of `columnFilter` & `alert`; Column Scope of `date` Columns) - where Date > 19 Dec 2021
- We have demonstrated some of these Predicates in Action by:
- Setting a [Column Filter](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) to the `Name` Column using the `Popular` Predicate
- Provided a [Conditional Style](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) for the `Language` Column that uses the `Vanilla` Predicate
- Created a Warning Alert for Date Columns that use the `Recent` Predicate
- Edit a date to be after 19 Dec 2021 and see the Alert appear
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Predicates',
predicateOptions: {
customPredicateDefs: [
{
id: 'big_github',
label: 'Popular',
columnScope: {
ColumnIds: ['name'],
},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
const githubStarsCount: number = params.node.data.github_stars;
const watchersCount: number = params.node.data.github_watchers;
return githubStarsCount > 50000 && watchersCount > 500 ? true : false;
},
},
{
id: 'vanilla',
label: 'Vanilla',
columnScope: {
ColumnIds: ['language'],
},
moduleScope: ['columnFilter', 'formatColumn'],
handler(params: PredicateDefHandlerContext) {
return params.value == 'JavaScript' || params.value == 'HTML';
},
},
{
id: 'recently_updated',
label: 'Recent',
columnScope: {
DataTypes: ['date'],
},
moduleScope: ['columnFilter', 'alert'],
handler(params: PredicateDefHandlerContext) {
const recentDate = new Date('2021-12-19');
return (params.value as Date) > recentDate;
},
},
],
},
initialState: {
FormatColumn: {
FormatColumns: [
{
Name: 'language-vanilla',
Style: {
BackColor: '#87cefa',
ForeColor: 'Black',
},
Scope: {
ColumnIds: ['language'],
},
Rule: {
Predicates: [
{
PredicateId: 'vanilla',
},
],
},
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-recently-updated',
Scope: {
DataTypes: ['date'],
},
Rule: {
Predicates: [
{
PredicateId: 'recently_updated',
},
],
},
AlertProperties: {
DisplayNotification: true,
},
MessageType: 'Warning',
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_issues_count',
'created_at',
'license',
],
ColumnFilters: [
{
ColumnId: 'name',
Predicates: [{PredicateId: 'big_github'}],
},
],
AutoSizeColumns: true,
},
],
},
},
};
```
### Adding Inputs
Some Custom Predicates might require an **additional** input value in order to perform the evaluation.
- Many [System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md) require inputs from users
- For instance `GreaterThan` compares the input value against base value and returns *true* if the latter is larger
The inputs property is an **array** of any type.
The reason it is an arrray is because while most inputs are a single value, some require 2 inputs (e.g. `Between`)
2 System Predicates - `In` and `NotIn` - can take an array of unlimited length
AdapTable will display an appropriate UI input for each value provided.
**Example: Custom Predicates with Inputs**
Creating Custom Predicates that receive inputs
- This demo creates a Custom Predicate Definition `Long String` which also receive an `input`
- It has `moduleScope` of `formatColumn` and `columnFilter` and a `columnScope` of String columns.
- It receives an input (of type number) which is used to verify whether the string is "big" (or not)
- We have created a Format Column on the Description with an input of 50 - so entries more than 50 characters are coloured
- Create a new Column Filter on the Lanague Column using the Long String Custom Predicate and an input of 5
- Note that the 2 rows with HTML will be filtered out
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Predicate Inputs',
predicateOptions: {
customPredicateDefs: [
{
id: 'long_string',
label: 'Long String',
columnScope: {DataTypes: ['text']},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
if (params.inputs) {
const input = params.inputs[0];
return (params.value as String).length > input;
}
return false;
},
inputs: [{type: 'number'}],
toString: ({inputs}) => `cell length > ${inputs[0]}`,
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['ColumnFilter'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'description',
'pushed_at',
'github_watchers',
'open_issues_count',
'created_at',
'license',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'pushed_at-format',
Scope: {
ColumnIds: ['pushed_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy, H:mm',
},
},
},
],
},
},
};
```
## Extending System Predicates
In addition to providing entire new Custom Predicates, developers can provide Custom Predicates which **extend** the System Predicates shipped by AdapTable.
This is done by using the `extends` property in the Predicate Definition which takes the PredicateId to override.
Extending System Predicates can be done in 2 ways depending on the behaviour required:
- **Replacing** the System Predicate - to do this provide the **same Id** as the Predicate being extended
- **Adding** alongside System Predicate - to do this provide a **different Id** to the Predicate being extended
**Example: Custom Predicates overriding System Predicates Behaviour**
Overriding System Date Predicates with Custom Predicates (with Timezone support)
- This example **overrides** 5 System Date Predicates with Custom Predicates that have Timezone support: `Today`, `Yesterday`, `Tomorrow`, `InPast`, `InFuture`
- We only override the `handler` for each of the System Predicates, and do not change any other properties
- However for `Today` we **provide a different Id** of `Now` - which means that both `Today` and `Now` appear in the dropdown (the latter at the bottom)
- The demo displays a list of tasks with due dates, which are all UTC dates, filtered according to the local time of the selected Timezone
- Note: The Timezone support (implemented using the [Luxon](https://moment.github.io/luxon/) library) is provided only for demonstration purposes and is not production ready!
- We use a local `ZonedDateTimeService` which is provided in [Adaptable Context](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context/index.md), making it available in all AdapTable's callbacks
- We also leverage the `systemFilterPredicates` property to remove other Date Predicates whose default implementation is not timezone compatible
- Change the Timezone via the `TimezoneSelect` component in the custom toolbar and/or the `Due Date` filter and observe the results
```ts
import * as React from 'react';
import {useRef} from 'react';
import {
Adaptable,
AdaptableApi,
AdaptableOptions,
AdaptableReadyInfo,
} from '@adaptabletools/adaptable-react-aggrid';
import {GridOptions} from 'ag-grid-enterprise';
// import adaptable css
import '@adaptabletools/adaptable-react-aggrid/index.css';
import './styles.css';
import {adaptableOptions} from './adaptableOptions';
import {gridOptions} from 'gridOptions';
import {agGridModules} from 'agGridModules';
import {ZonedDateTimeService} from './ZonedDateTimeService';
import {getRowData} from './rowData';
const App: React.FunctionComponent = () => {
const adaptableApiRef = useRef(null);
const zonedDateTimeServiceRef = useRef(
new ZonedDateTimeService()
);
const adaptOptions = useRef({
...adaptableOptions,
adaptableContext: {
zonedDateTimeService: zonedDateTimeServiceRef.current,
},
});
const agGridOptions = useRef({
...gridOptions,
rowData: getRowData(),
});
return (
{
// save a reference to adaptable api
adaptableApiRef.current = adaptableReadyInfo.adaptableApi;
}}>
`;
}
getGui() {
return this.eGui;
}
}
export const columnDefs: (ColDef | ColGroupDef)[] = [
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
{
field: 'name',
cellDataType: 'text',
sortable: true,
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
// groupId: 'demoColGroup',
headerName: 'Special Columns',
children: [
{
// it has to be the same ID as for the CalculatedColumn
colId: 'subscribersRatio',
// the type has to be specified as 'calculatedColumn' (or [...,'calculatedColumn'])
type: [AdaptableColumnType.CalculatedColumn],
cellDataType: 'number',
tooltipValueGetter: (params: ITooltipParams) => params.data,
tooltipComponent: CustomTooltip,
tooltipComponentParams: {
color: 'var(--ab-color-accentlight)',
backgroundColor: 'var(--ab-color-primary-foreground)',
},
},
{
// it has to be the same ID as for the FreeTextColumn
colId: 'comments',
// the type has to be specified as 'freeTextColumn' (or [...,'freeTextColumn'])
type: AdaptableColumnType.FreeTextColumn,
cellDataType: 'number',
headerTooltip:
'This is a free text column, you can use it to store any data you want',
},
],
},
{
field: 'license',
cellDataType: 'text',
editable: false,
enablePivot: true,
enableRowGroup: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{
field: 'has_wiki',
headerName: 'Has Wiki',
cellDataType: 'boolean',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
];
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
tooltipShowDelay: 500,
};
```
#### Special Column Properties
AdapTable provides a large set of property options for [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [FreeText](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) Columns (e.g. `Filterable`, `Groupable` etc.)
But sometimes developers will want to add additional properties.
This is achieved by supplying the Column Types in AG Grid Column Definitions, which they (and end users) can then attach to the Special Column.
This is particularly useful when you have defined bespoke AG Grid Column Types and you want to extend them to columns created at run-time in AdapTable.
The list of additional column type options to show to the run-time user is also defined (like with Scope - see above) in the `columnTypes` property in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md).
### Pivot Total Columns
Another use case for using Column Types in AdapTable is when formatting [Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md).
AdapTable provides 3 types of Pivot Total Columns each of which is given its own `type` property value:
| Pivot Total Column | Value for `type` property | AdaptableColumnType Value |
| ----------------------- | ------------------------- | ------------------------- |
| Pivot Grand Total | `pivotGrandTotal` | ּּ`PivotGrandTotal` |
| Pivot Column Total | `pivotColumnTotal` | ּּ`PivotColumnTotal` |
| Pivot Aggregation Total | `pivotAggregationTotal` | ּּ`PivotAggregationTotal` |
- There is also a `PivotAnyTotal` column type available (string value is `pivotAnyTotal`)
- This can be used to display **all** of the 3 Total Column types, particularly useful when formatting and styling
See [Creating Pivot Total Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-total-columns/index.md) for more information
### Hidden Columns
A further use case for using Column Types in AdapTable is when [hiding a Column altogether](https://www.adaptabletools.com/docs/dev-guide-columns-hiding-columns/index.md).
This can be done by setting the column type to `hiddenColumn`.
Columns marked with this type will not be:
- rendered in the Grid
- available in the Layout Wizard Editor
- listed in the Columns Tool Panel
However they will be available in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) in order to use it to create Expressions.
See [Hiding Columns in AdapTable](https://www.adaptabletools.com/docs/dev-guide-columns-hiding-columns/index.md) for more details and a demo
---
# Configuring AG Grid Column Defs at Design Time
Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-configuring-coldefs
- AdapTable treats each AG Grid ColDef property on a case by case basis
- This page anaylses the different use cases and the general principles involved
AG Grid users define the columns in the Grid using the `colDefs` property in Grid Options.
This step is **mandatory** for AdapTable users, also, who will then reference the ColDef Id in their Layouts.
However not all properties in ColDefs are treated equally by AdapTable - some are ignored, some are required and others are used only if the preferred alternative in AdapTable is not provided.
The full details of how AdapTable treats each ColDef property are listed below.
AG Grid and AdapTable each have a mechanism for developers to provide information about Grid Columns:
- [AG Grid ColDef Properties](https://ag-grid.com/javascript-data-grid/column-properties/#reference-display) - define column behaviour across the Grid
- [AdapTable Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) - define Column behaviour and properties for named sets of Columns
The fundamental difference between the 2 properties is **Scope Usage**.
- **ColDefs set full and exclusive Column behaviour** for the lifetime of the Application
- **Layouts support multiple, mutually exclusive use cases** - Columns can behave differently in different Layouts
Because AdapTable supports multiple Layouts, it cannot simply just read the properties defined in ColDefs.
- This is because 2 different Layouts might want to treat the same Column property differently
- For instance it is very common to set different visibility, column order, or row grouping in different Layouts
As a result, AdapTable needs to decide on initial Layout behaviour on a per-ColDef property basis.
Essentially, AdapTable responds to AG Grid ColDef properties in 3 different ways.
Depending on the use case, it will do one of the following for each property:
- **ignore** - the property is **never** invoked or used
- **respect** - if provided, AdapTable will use it in its own functionality
- AdapTable generally **ignores** ColDef props that sets same **values** as available in Layouts, e.g. `group`, `pivot`, `pin`
- But **respects** (usually in Layout Editor) ColDef props that set **behaviour** e.g. `enableGroup`, `enableValue`, `resizable`
- **fall back on** - property still works if **AdapTable's preferred implementation** is not provided
- The majorify of AG Grid's `ColDef` properties do not appear in any of these 3 lists
- This is because AdapTable has no direct relationship with them, and they perform their intended AG Grid purpose
---------------
### Ignored
There are some ColDef properties which AdapTable simply ignores - they are never read nor acted upon.
The intended behaviour needs, instead, to be provided via AdapTable's Layout properties.
#### Pivoting
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| ------------------- | ---------------------- | ------------------------------------------- |
| `pivot` | Pivots a Column | Only columns in `PivotColumns` are pivoted |
| `initialPivot` | Pivots new Column | Only columns in `PivotColumns` are pivoted |
| `pivotIndex` | Pivot Column index | Columns are pivoted by `PivotColumns` order |
| `initialPivotIndex` | New Pivot Column index | Columns are pivoted by `PivotColumns` order |
#### Row Grouping
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| ---------------------- | ------------------------ | --------------------------------------------- |
| `rowGroup` | Groups a Column | Only columns in `RowGroupColumns` are grouped |
| `initialRowGroup` | Groups new Column | Only columns in `RowGroupColumns` are grouped |
| `rowGroupIndex` | Grouped Column index | Columns grouped by `RowGroupColumns` order |
| `initialRowGroupIndex` | New Grouped Column index | Columns grouped by `RowGroupColumns` order |
#### Aggregating
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| ---------------- | --------------- | ------------------------------------------------------------ |
| `aggFunc` | Agg Func | Only Aggregations in `TableAggregationColumns` are evaluated |
| `initialAggFunc` | New Agg Func | Only Aggregations in `TableAggregationColumns` are evaluated |
#### Pinning
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| --------------- | ------------------------- | ------------------------------------------- |
| `pinned` | Pins a Column | Only columns in `ColumnPinning` are pinned |
| `initialPinned` | Pins new Column | Only columns in `ColumnPinning` are pinned |
| `lockPinned` | Prevents Pinning a Column | Column can still be pinned in Layout and UI |
#### Sorting
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| ------------------ | ------------------------ | -------------------------------------------- |
| `sort` | Sorts a Column | Only columns in `ColumnSorts` are sorted |
| `initialSort` | Sorts new Column | Only columns in `ColumnSorts` are sorted |
| `sortIndex` | Sorted Column index | Columns sorted by the order in `ColumnSorts` |
| `initialSortIndex` | New Sorted Column index | Columns sorted by the order in `ColumnSorts` |
| `sortingOrder` | Order of Sort Directions | Sort Directions provided in `ColumnSorts` |
#### Visibility
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| ------------- | ------------------ | -------------------------------------------------------------------------------- |
| `hide` | Hides a Column | Any column in `TableColumns` is visible (unless overridden in `ColumnVisibility`) |
| `initialHide` | Hides a new Column | Any column in `TableColumns` is visible (unless overridden in `ColumnVisibility`) |
#### Sizing
| ColDef | AG Grid Purpose | AdapTable Layout Behaviour |
| -------------- | --------------------- | ------------------------------------- |
| `initialWidth` | Width for new Columns | Only sizing in `ColumnSizing` is used |
| `initialFlex` | Flex for new Columns | Only sizing in `ColumnSizing` is used |
- Unlike with most other ColDef properties that have values, `flex` and `width` are not ignored by AdapTable
- Instead they are used if the Column's property is not explicitly overridden in the Layout's `ColumnSizing`
---------------
### Leveraged
There are many ColDef properties which, if provided, are respected - and used - by AdapTable:
| ColDef | AG Grid Purpose | AdapTable Behaviour |
| ----------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `field` | Finds item in Grid Data Source | Becomes [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) `field` property |
| `colId` | Unique Id for Column | Becomes [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) `columnId` property |
| `type` | Used for Column Templating | Used for [Column Types Scope](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) |
| `cellDataType` | Column's data type | Used to infer [Adaptable Column's Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) |
| `enablePivot` | Column is Pivotable in UI | Respected by [Pivot Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-pivot/index.md) |
| `enableRowGroup` | Column is Groupable in UI | Respected by [Table Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) |
| `enableValue` | Column is Aggregatable in UI | Respected by [Pivot Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-pivot/index.md) |
| `defaultAggFunc` | Default Agg Func | Respected by [Table Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) |
| `allowedAggFuncs` | Allowed Agg Funcs | Respected by [Table Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) |
| `sortable` | Column is Sortable in UI | Respected by [Table Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) |
| `resizable` | Column is Resizable in UI | Respected by [Table Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) |
| `suppressMovable` | Column is not Movable in UI | Respected by [Table Layout UI Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md) |
- The `resizable` prop is only used if not explicitly overridden by `Resizable` in the Layout's `ColumnSizing` object
- The `allowedAggFuncs` prop is also used to set which AdapTable Aggregations (e.g. `only`) are available in Layouts
---------------
### AdapTable Preference
There are a few AG Grid ColDef properties for which AdapTable provides an alternative implementation.
These properties **will** be evaluated, but only if the AdapTable equivalent has not been provided.
- We **strongly** recommend using the AdapTable equivalent in all these use cases where possible
- Any objects created are saved to AdapTable State and there is tight integration with other AdapTable features
| ColDef | AG Grid Purpose | Preferred AdapTable Equivalent |
| ---------------- | ----------------------- | ---------------------------------------------------------------------------------------------------- |
| `valueFormatter` | Formats a Cell | [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) |
| `comparator` | Provides custom sort | [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) |
| `editable` | Sets Column Editability | [AdapTable Cell Editability](https://www.adaptabletools.com/docs/dev-guide-tutorial-setting-cell-editability/index.md) |
In addition, the Layout's `ColumnSizing` object contains 5 properties which override ColDef props.
However if one of these is not provided, then the ColDef equivalent is used instead:
| AdapTable `ColumnSizing` Property Used if Provided | ColDef Fallback property |
| -------------------------------------------------- | ------------------------ |
| `Flex` | `flex` |
| `Width` | `width` |
| `MinWidth` | `minWidth` |
| `MaxWidth` | `maxWidth` |
---
# Hiding Columns
Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-hiding-columns
- AdapTable allows Columns to be defined as Hidden, by setting a type of `hiddenColumn` in ColDefs
- Hidden Columns are never visible in the Grid (or the AdapTable UI) but can be used in Expressions
Columns can be hidden in AdapTable so that they are never displayed in the UI.
This is especially useful if you are using a primary key column which you do not want users to see or edit.
- A hidden Column will be still be listed in the Columns section of the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and in the [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md)
- This allows it to form part of an Expression (e.g. to be used in [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) or the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md))
This is done setting (or adding) `hiddenColumn` to the `type` property in the AG Grid ColdDef definition.
- Alternatively you can use the `AdaptableColumnType.HiddenColumn` constant
- See the [Guide to Providing Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) for more information of setting column types
```ts {6,11}
// Add 2 hidden columns
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number'
type: 'hiddenColumn'
},
{
field: 'map',
cellDataType: 'text'
type: AdaptableColumnType.HiddenColumn
},
]
```
- AG Grid offers a similar ColDef property named `hide` which if set to *true* will hide the Column
- AdapTable [ignores this property](https://www.adaptabletools.com/docs/dev-guide-columns-configuring-coldefs/index.md) and sets visibility based purely on [Layout properties](https://www.adaptabletools.com/docs/handbook-layouts-table-column-visibility/index.md) and the `hiddenColumn` type
**Example: Hiding a Column in AdapTable UI**
Hide a column so its never visible to a user
- In this example we "hide" the `Github Watchers` and `Github Stars` Columns by setting their ColDef `type` property to *HiddenColumn*
- As a result they are not visible in the Grid, nor in the `Columns` [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) and nor the Layout Wizard
- However they are stil available for use in [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md)
- Open Columns [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) and note the `Github Watchers` and `Github Stars` Columns are not listed (but the Calculated Column `Github Total` is listed)
- Edit the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md), or the `Github Total` [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md), and note `Github Watchers` & `Github Stars` Columns are referenced in the Expression and available in [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) and [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md)
- Note also that we set the `Name` column with *hide* in ColDefs but that gets ignored by AdapTable and the column is displayed (as its in the Layout)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Hiding A Column',
initialState: {
Theme: {CurrentTheme: 'dark'},
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
PinnedToolbars: ['GridFilter'],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'helll',
'name',
'language',
'license',
'github_stars',
'github_total',
'open_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
GridFilter: {
Expression: '[github_watchers] > 20500 OR [github_stars] > 8500',
},
AutoSizeColumns: true,
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'github_total',
FriendlyName: 'Github Total',
Query: {
ScalarExpression: '[github_watchers] + [github_stars]',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
Width: 200,
},
},
],
},
},
};
```
```ts
import {AdaptableColumnType} from '@adaptabletools/adaptable';
import {ColDef} from 'ag-grid-enterprise';
import {WebFramework} from 'rowData';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
editable: false,
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
type: AdaptableColumnType.HiddenColumn,
},
{
field: 'name',
cellDataType: 'text',
sortable: true,
hide: true, // this is ignored by AdapTable
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
type: AdaptableColumnType.HiddenColumn,
},
{
field: 'license',
cellDataType: 'text',
editable: false,
enablePivot: true,
enableRowGroup: true,
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{
field: 'has_wiki',
headerName: 'Has Wiki',
cellDataType: 'boolean',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
];
```
- Prior to [AdapTable 21](https://www.adaptabletools.com/support/version-210-release-note) fully hidden columns could only be achieved by a combination of 4 `ColDef` properties
- These needed explicitly setting to true: `hide`, `lockVisible`, `suppressColumnsToolPanel`, `suppressFiltersToolPanel`
---
# Managing AG Grid Column Defs at RunTime
Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-managing-runtime
- AdapTable helps developers manage AG Grid Column Definitions easily and safely updated at runtime
- Two convenience functions reduce the update's complexity while ensuring AdapTable's [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) work smoothly
- Other functions enable Column Definitions to be safely addded and removed at runtime
AG Grid's Column Definitions are **immutable**.
Nevertheless, AG Grid still makes it possible, at runtime, to add, update or delete ColDefs.
AdapTable supports this functionality via bespoke "wrapper" functions to ensure everything hangs together.
These functions ensure that AG Grid columns are added, updated or deleted correctly, while also ensuring AdapTable's [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) and other features to run smoothly.
- **We strongly recommend you use AdapTable's API functions** (listed below) when managing AG Grid columns
- AdapTable will invoke the related AG Grid function, but in a way that ensures everything hangs together properly
## Updating ColDefs
AG Grid distinguishes betweeen 2 types of Column properties - **stateful** and **non-stateful**.
It provides 2 complementary sets of `GridAPI` functions to update column props based on this distinction:
- For the reduced set of "stateful" Column properties the [AG Grid Column State API](https://www.ag-grid.com/javascript-data-grid/column-state/) is recommended
- For all other Column properties [AG Grid's Grid API](https://www.ag-grid.com/javascript-data-grid/column-updating-definitions/) should be used
AdapTable fully supports AG Grid Column immutability, and also how columns can be updated at run-time.
AdapTable's [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) contains 2 sets of complementary functions to mirror those provided by AG Grid.
- AdapTable provides 2 different sets of methods for stateful and non-stateful Column properties
- However the shape of the object that is passsed into each function is identical
### Stateful Properties
As noted above, AG Grid defines a subset of column properties as [Column State](https://www.ag-grid.com/javascript-data-grid/column-updating-definitions/#changing-column-state).
These are properties which can be updated without needing to provide a full new set of Column definitions.
AdapTable provides the `updateAgGridColumnState` function in [`GridApi`](https://www.adaptabletools.com/docs/reference/gridapi.md) to update the Column State for a Column in a safe way.
A parallel `updateAgGridColumnStates` function can be used to update the Column State for **multiple** columns
### `updateAgGridColumnState`
Updates the Column State for a given Column
The function take an AG Grid Column State object (of type `ColumnState`) and returns void.
You should pass in an object that contains the `colId` of the column and whichever stateful property (or properties) you want to change:
```ts
// Hide the Rating column
adaptableApi.gridApi.updateAgGridColumnState({
colId: 'rating',
hide: true,
});
```
The function will, in turn, call AG Grid's `applyColumnState` function in AG Grid Api in a managed way.
**Example: Updating Stateful Column Props at Runtime**
How to safely update AG Grid Column properties using Column State at run-time
- In this demo a Custom Dashboard Toolbar contains 3 buttons that each update **stateful** AG Grid Column props using the `updateAgGridColumnState` function:
- The `Name` column is widened using `width`
- The `Langague` column is hidden using `hide`
- The `Github Stars` column is sorted and pinned using `sort` and `pin`
### Expand to see how the Column Definitions are updated
```ts
context.adaptableApi.gridApi.updateAgGridColumnState({
colId: 'name',
width: 300,
});
context.adaptableApi.gridApi.updateAgGridColumnState({
colId: 'language',
hide: true,
});
context.adaptableApi.gridApi.updateAgGridColumnState({
colId: 'github_stars',
pinned: 'right',
sort: 'asc',
});
```
- Click each button in turn and see how they update
```ts
import {
AdaptableButton,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Updating Stateful Column Defs',
dashboardOptions: {
customToolbars: [
{
name: 'Custom Buttons',
toolbarButtons: [
{
label: 'Widen Name Column',
buttonStyle: {
tone: 'info',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.updateAgGridColumnState({
colId: 'name',
width: 300,
});
},
},
{
label: 'Hide Language Column',
buttonStyle: {
tone: 'success',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.updateAgGridColumnState({
colId: 'language',
hide: true,
});
},
},
{
label: 'Sort & Right-Pin Github Stars Column',
buttonStyle: {
tone: 'warning',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.updateAgGridColumnState({
colId: 'github_stars',
pinned: 'right',
sort: 'asc',
});
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['Custom Buttons'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
### Non-Stateful Properties
Adaptable also fully supports updating Column properties which are not stateful.
This is done using the `updateAgGridColumnDefinition` function in [`GridApi`](https://www.adaptabletools.com/docs/reference/gridapi.md).
### `updateAgGridColumnDefinition`
Updates non-stateful properties in an AG Grid Column
The function take a [`ColDefWithId`](https://www.adaptabletools.com/docs/reference/coldefwithid.md) object and returns void.
The `ColDefWithId` object is essentially an AG Grid Column Definition with a **mandatory** `coldId` property.
To use the function, you need to pass in an object that contains the `colId` of the column and whichever non-stateful property (or properties) you want to change:
```ts
// Change the type and editable properties of the Rating column
adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'rating',
type: ['newCustomType'],
editable: true
});
```
**Example: Updating Other Column Props at Runtime**
How to safely update non-stateful AG Grid Column properties at run-time
- In this example the Custom Dashboard Toolbar again contains 3 buttons that each updates a Column Definition property
- But as these are **non-stateful** AG Grid Column props, the `updateAgGridColumnDefinition` function is used:
- The `Name` column is given a new `headerName` of 'Framework'
- The `License` column has `editable` set to *true*
- The `Issue Change` column is given a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) of 'Github' (because an existing [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) has a Scope of that Column Type, the `Issue Change` Column is automatically styled)
### Expand to see how the Column Definitions are updated
```ts
context.adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'name',
headerName: 'Framework',
});
context.adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'license',
editable: true,
});
context.adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'week_issue_change',
type: ['github'],
});
```
- Click each button in turn and see how they update
```ts
import {
AdaptableButton,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Updating Non Stateful Column Defs',
columnOptions: {
columnTypes: ['github'],
},
dashboardOptions: {
customToolbars: [
{
name: 'Custom Buttons',
toolbarButtons: [
{
label: 'Change Name Column Header',
buttonStyle: {
tone: 'info',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'name',
headerName: 'Framework',
});
},
},
{
label: 'Make License Editable',
buttonStyle: {
tone: 'success',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'license',
editable: true,
});
},
},
{
label: 'Change Issue Change Style',
buttonStyle: {
tone: 'warning',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.updateAgGridColumnDefinition({
colId: 'week_issue_change',
type: ['github'],
cellDataType: 'number',
});
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['Custom Buttons'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'week_issue_change',
'github_watchers',
'github_stars',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github',
Scope: {
ColumnTypes: ['github'],
},
Style: {
ForeColor: 'LightBlue',
FontWeight: 'Bold',
Alignment: 'Center',
},
},
],
},
},
};
```
## Adding & Removing ColDefs
AdapTable's [`GridApi`](https://www.adaptabletools.com/docs/reference/gridapi.md) contains 3 functions to safely add and remove AG Grid Column Definitions at run-time:
- `addAgGridColumnDefinition` - adds one ColumnDef
- `removeAgGridColumnDefinition` - removes one ColumnDef
- `setAgGridColumnDefinitions` - adds a group of ColumnDefs
- Always use these function when adding new Columns, or removing existing Columns, at runtime
- AdapTable will make sure to add or remove column in ColumnDefs correctly and ensure everything works
### Adding ColDefs
The `addAgGridColumnDefinition` function enables a new AG Grid Column Definition to be added at run-time.
### `addAgGridColumnDefinition`
Adds new AG Grid Columns
The function take a [`ColDefWithId`](https://www.adaptabletools.com/docs/reference/coldefwithid.md) object and returns void.
The `ColDefWithId` object is essentially an AG Grid Column Definition with a mandatory `coldId` property.
To use the function, you need to pass in an object that contains the `colId` of the column and whichever properties you want the Column to have:
```ts
// Provide a Rating column
adaptableApi.gridApi.addAgGridColumnDefinition({
colId: 'rating',
field: 'fitch',
width: 200,
editable: false,
cellDataType: 'text'
});
```
**Example: Adding Column Definitions at Runtime**
How to safely add AG Grid Column Definitions at run-time
- In this example we provide a button that adds a `Forks Count` column using the `addAgGridColumnDefinition` function
- We then use the `updateCurrentLayout` function in [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) to update the Layout to include the newly created column (see [Updating Layouts](https://www.adaptabletools.com/docs/handbook-layouts-updating/index.md) for more details)
### Expand to see how the Column Definition is added
```ts
context.adaptableApi.gridApi.addAgGridColumnDefinition({
colId: 'forks_count',
headerName: 'Forks Count',
field: 'forks_count',
width: 200,
cellDataType: 'number'
});
```
- Click the button to add a `Forks Count` column (and note how it is added to the Layout)
```ts
import {
AdaptableButton,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Adding Column Defs',
dashboardOptions: {
customToolbars: [
{
name: 'Custom Buttons',
toolbarButtons: [
{
label: 'Add Forks Count Column',
buttonStyle: {
tone: 'info',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.addAgGridColumnDefinition({
colId: 'forks_count',
headerName: 'Forks Count',
field: 'forks_count',
width: 200,
cellDataType: 'number',
});
context.adaptableApi.layoutApi.updateCurrentLayout(layout => {
layout.TableColumns?.push('forks_count');
return layout;
});
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['Custom Buttons'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'week_issue_change',
'github_watchers',
'github_stars',
],
},
],
},
},
};
```
### Removing ColDefs
The `removeAgGridColumnDefinition` function enables safe run-time deletion of existing AG Grid ColDefs.
### `removeAgGridColumnDefinition`
Removes existing AG Grid Columns
The function takes the `colId` of the Column to be removed and returns void:
```ts
// Remove the Rating column
adaptableApi.gridApi.removeAgGridColumnDefinition('rating');
```
**Example: Deleting Column Definitions at Runtime**
How to safely add AG Grid Column Definitions at run-time
- In this example we provide a button that deletes the `License` column using the `removeAgGridColumnDefinition` function.
### Expand to see how the Column Definition is deleted
```ts
context.adaptableApi.gridApi.removeAgGridColumnDefinition('license');
```
- Click the button to remove the `License` column
```ts
import {
AdaptableButton,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Deleting Column Defs',
dashboardOptions: {
customToolbars: [
{
name: 'Custom Buttons',
toolbarButtons: [
{
label: 'Delete License Column',
buttonStyle: {
tone: 'info',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.removeAgGridColumnDefinition(
'license'
);
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['Custom Buttons'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'week_issue_change',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'github_stars',
],
AutoSizeColumns: true,
},
],
},
},
};
```
### Setting ColDefs
The `setAgGridColumnDefinitions` function enables setting multiple AG Grid Column Definitions at run-time in a single step.
### `setAgGridColumnDefinitions`
Set multiple AG Grid Columns
The function takes an array of AG Grid `ColDef` (or `ColGroupDef`) objects and returns void.
```ts
// Set a group of AG Grid Col Defs
adaptableApi.gridApi.setAgGridColumnDefinitions(colDefs);
```
**Example: Setting Column Definitions at Runtime**
How to safely replace AG Grid Column Definitions at run-time
- In this example the grid starts with many columns visible
- Clicking the button replaces **all** Column Definitions in a single step using the `setAgGridColumnDefinitions` function
- The new set contains just 4 columns: `Framework`, `Language`, `GitHub Stars` and `License`
- The current [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) is also updated so it stays in sync with the new columns (see [Updating Layouts](https://www.adaptabletools.com/docs/handbook-layouts-updating/index.md) for more details)
### Expand to see how the Column Definitions are set
```ts
const compactColumnDefs = [
{
colId: 'name',
field: 'name',
headerName: 'Framework',
cellDataType: 'text',
width: 200,
},
{
colId: 'language',
field: 'language',
cellDataType: 'text',
width: 150,
},
{
colId: 'github_stars',
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
width: 150,
},
{
colId: 'license',
field: 'license',
cellDataType: 'text',
width: 180,
},
];
context.adaptableApi.gridApi.setAgGridColumnDefinitions(compactColumnDefs);
context.adaptableApi.layoutApi.updateCurrentLayout(layout => {
layout.TableColumns = ['name', 'language', 'github_stars', 'license'];
return layout;
});
```
- Click the button to replace the Column Definitions with the compact set (and note how the Layout is updated)
```ts
import {
AdaptableButton,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
const compactColumnDefs = [
{
colId: 'name',
field: 'name',
headerName: 'Framework',
cellDataType: 'text',
width: 200,
},
{
colId: 'language',
field: 'language',
cellDataType: 'text',
width: 150,
},
{
colId: 'github_stars',
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
width: 150,
},
{
colId: 'license',
field: 'license',
cellDataType: 'text',
width: 180,
},
];
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Setting Column Defs',
dashboardOptions: {
customToolbars: [
{
name: 'Custom Buttons',
toolbarButtons: [
{
label: 'Set Compact Column Definitions',
buttonStyle: {
tone: 'info',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.gridApi.setAgGridColumnDefinitions(
compactColumnDefs
);
context.adaptableApi.layoutApi.updateCurrentLayout(layout => {
layout.TableColumns = [
'name',
'language',
'github_stars',
'license',
];
return layout;
});
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['Custom Buttons'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'week_issue_change',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'github_stars',
],
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Managing Columns in AdapTable
Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-overview
- This section provides a few pages relating to setting up and managing Columns in AdapTable
Columns are at the core of AdapTable and AG Grid, and are primarily managed via [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md).
There are many Column-related features and tips which are covered in this section.
---
# Column Scope
Canonical page: https://www.adaptabletools.com/docs/dev-guide-columns-scope
- Column Scope defines in which columns a given AdapTable feature is applied
- It can be comprise named Columns, Data Types, Column Types or a whole Row
Column Scope specifies **where** an AdapTable Feature can be applied.
It sets which columns any given [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) will be evaluated for.
The [`Column Scope`](https://www.adaptabletools.com/docs/reference/columnscope.md) object has 4 main types of values:
Typically, Scope will include only of these 4 types
- **All** - This will include every Column in a Row
- **Column(s)** - An array of *ColumnId*s
- **Data Type(s)** - An array of [Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) (available values are: `text`, `number`, `boolean` and `date`)
- **Column Type(s)** - An array of strings which specify which [Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) to use
## Where Column Scope is Used
Column Scope is used widely in AdapTable in both [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) sections and [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
Some of the usage for Column Scope includes:
- [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md)
- [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md)
- [Custom Sort Comparers](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md#comparer-function)
- [Export](https://www.adaptabletools.com/docs/handbook-exporting/index.md) (used in [Custom Reports](https://www.adaptabletools.com/docs/handbook-exporting-reports-custom/index.md))
- [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md)
- [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md)
- [Shortcuts](https://www.adaptabletools.com/docs/handbook-editing-shortcut/index.md)
This allows you greater flexibility when creating objects. For instance you can set:
- one Format Column for all Numeric columns (e.g. Green Font for Positive values)
- a Data Validation Alert for a given set of named columns
- a Display Format for all Columns of a bespoke Column Type (e.g. 'pricing')
- a subset of columns to be exported in a Report
## Using Column Scope
The Adaptable UI makes it easy to set the Column Scope of an object that is being created or edited.
### Setting Column Scope in a Settings Panel Wizard
These are the steps involved:
There are usually (depending on the Module) 4 Radio Buttons:
- All Columns - maps to a scope of `All`
- Selected Columns - maps to a scope of `ColumnIds`
- Data Types - maps to a scope of `DataTypes`
- Column Types - maps to a scope of `ColumnTypes`
Clicking the *All Columns* button does not require any extra step.
Typically you will use the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) in a future step to create an [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md).
Clicking the *Columns* button will display a list of all the Columns in AG Grid.
Click the Columns you want in your Scope - you will see them appear in a list at the bottom.
You can choose to see only the Selected Columns in the wizard.
Clicking the *Data Types* button will display a list of Checkboxes with available [Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md).
This is typically (unless you are using a Module with reduced DataType Scope like [Shortcuts](https://www.adaptabletools.com/docs/handbook-editing-shortcut/index.md)):
- date
- number
- text
- boolean
See [Cell Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) for more details
Clicking the *Column Types* button will display a list of Checkboxes with available Column Types.
This list is derived from the values provided in the `columnTypes` prop in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) (which can either supply a list of Column Types or a function that returns a list).
See [Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) for detailed information on how to provide and use Column Types
## Configuring Column Scope
It is very straightforward to set Column Scope in [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md):
### Scope: All
To set a Scope of `All` (i.e. the whole row) you need to set 'All' to **true**:
```ts {1}
Scope: { All: true }
```
- This is typically done when the object uses an [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) rather than a [Predicate](https://www.adaptabletools.com/docs/adaptable-predicate/index.md)
- Esentially it will operate over the whole row rather than individual columns
### Scope: ColumnIds
To set a Scope on one or more Columns, simply provide an array of `ColumnIds`values:
```ts {1}
Scope: { ColumnIds: ['ItemCost', 'Package Cost', 'OrderCost'] }
```
### Scope: Data Types
To set a Scope of one or more [Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) (e.g. number, text), provide an array of `DataTypes` values:
```ts {1}
Scope: { DataTypes: ['number'] }
```
### Scope: Column Types
To set a Scope of one or more [Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md), provide an array of strings that contain available `ColumnTypes`:
```ts {1}
Scope: { ColumnTypes: ['number-column', 'price', 'calculatedColumn'] }
```
### Scope: Multiple Sections
It is possible - albeit rare - to provide multiple Scope types (e.g. DataType and ColumnIds).
For instance to use [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) to format all `date` Columns plus 3 other Columns you could do:
```ts {2,3}
Scope: {
DataTypes: ['date'],
ColumnIds: ['country', 'currency', 'counterparty']
},
```
----------------
## Scope API
The Scope API section of Adaptable API contains a number of methods for managing Column Scope:
| Method | Returns | Description |
| --- | --- | --- |
| [areAllBooleanColumnsInScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#areallbooleancolumnsinscope) | `boolean` | True if all selected columns are boolean |
| [createCellColorRangesForScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#createcellcolorrangesforscope) | [`CellColorRange`](https://www.adaptabletools.com/docs/reference/cellcolorrange.md)`[]` | Creates a default single `CellColorRange` for Styled Column wizards (Gradient, Percent Bar, Bullet Chart): `Col-Min` → `Col-Max` with neutral gray, matching the colour used when adding a range in the Ranges UI. If the column has no sample values yet, returns one `0` → `0` gray range. |
| [getAnyColumnIdForScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getanycolumnidforscope) | `string \| undefined` | Gets any ColumnId from the Scope |
| [getColumnIdsInScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getcolumnidsinscope) | `string[] \| undefined` | Returns all the ColumnIds in the Scope |
| [getColumnsInScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getcolumnsinscope) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`[]` | Returns list of all Columns in the given Scope |
| [getColumnTypesInScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getcolumntypesinscope) | `string[] \| undefined` | Returns all the ColumnTypes in the Scope |
| [getDataTypesInScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getdatatypesinscope) | `ScopeDataType[] \| undefined` | Returns all the DataTypes in the Scope |
| [getScopeDescription(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getscopedescription) | `string` | Provides a description for the Scope |
| [getScopeToString(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getscopetostring) | `string` | Gets string representation of the Scope |
| [getSingleColumnInScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#getsinglecolumninscope) | `string \| undefined` | Gets the only Column in given Scope |
| [isColumnInDateScope(column, scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#iscolumnindatescope) | `boolean` | True if Scope has Data DataType which contains Column |
| [isColumnInNumericScope(column, scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#iscolumninnumericscope) | `boolean` | True if Scope has Numeric DataType containing Column |
| [isColumnInScope(column, scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#iscolumninscope) | `boolean` | True if Column is in given Scope |
| [isColumnInScopeColumns(column, scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#iscolumninscopecolumns) | `boolean` | True if Column is in Scope's 'ColumnIds' section |
| [isColumnInTextScope(column, scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#iscolumnintextscope) | `boolean` | True if Scope has text DataType containing Column |
| [isPrimaryKeyColumnInScopeColumns(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#isprimarykeycolumninscopecolumns) | `boolean` | Whether PK column is included in Scope's column section |
| [isScopeInScope(scopeA, scopeB)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#isscopeinscope) | `boolean` | True if first scope is in second Scope |
| [isSingleBooleanColumnScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#issinglebooleancolumnscope) | `boolean` | True if Scope contains just 1 boolean Column |
| [isSingleColumnScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#issinglecolumnscope) | `boolean` | True if Scope contains just 1 ColumnId |
| [isSingleNumericColumnScope(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#issinglenumericcolumnscope) | `boolean` | True if Scope contains just 1 numeric Column |
| [scopeHasColumns(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#scopehascolumns) | `boolean` | True if Scope contains ColumnIds |
| [scopeHasColumnType(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#scopehascolumntype) | `boolean` | True if Scope contains ColumnTypes |
| [scopeHasDataType(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#scopehasdatatype) | `boolean` | True if Scope contains DataTypes |
| [scopeHasOnlyBooleanDataType(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#scopehasonlybooleandatatype) | `boolean` | True if Scope is DataTypes and contains just 'Boolean' |
| [scopeIsAll(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#scopeisall) | `boolean` | True if Scope is 'All' |
| [scopeIsEmpty(scope)](https://www.adaptabletools.com/docs/reference/columnscopeapi.md#scopeisempty) | `boolean` | True if Scope is empty |
---
# Base Context
Canonical page: https://www.adaptabletools.com/docs/dev-guide-common-base-context
- Base class used for all Context objects provided in functions in Adaptable Options
- Also the base class for all EventInfo objects used by AdapTable Events
The Base Context object provides a set of useful properties, including the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md).
It acts as the Base Class for 2 large sets of commonly-used classes in AdapTable:
- All `xxxContext` objects provided to properties in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) that take the form of functions
- All `xxxEventInfo` objects published by [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md)
## Base Context Object
The [`BaseContext`](https://www.adaptabletools.com/docs/reference/basecontext.md) object is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [adaptableApi](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable Api object |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
| [adaptableId](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptableid) | `string` | Id of current AdapTable instance |
| [adaptableStateKey](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptablestatekey) | `string` | Current Adaptable State Key |
| [clientTimestamp](https://www.adaptabletools.com/docs/reference/basecontext.md#clienttimestamp) | `Date` | Time on user's computer |
| [userName](https://www.adaptabletools.com/docs/reference/basecontext.md#username) | `string` | Name of Current User |
---
# Integrated Examples
Canonical page: https://www.adaptabletools.com/docs/dev-guide-integrated-examples-overview
Generally, the [Demos](https://www.adaptabletools.com/docs/documentation-demo-list/index.md) in this documentation are designed to show one particular feature or option.
This allows users to focus on the particular AdapTable feature in depth
By contrast, this section contains examples that integrate 2 or more AdapTable features together.
---
# Modules
Canonical page: https://www.adaptabletools.com/docs/dev-guide-modules
This is the Developer Guide for Modules
Need to explain what they are and how they work and what they do.
No need to list anything.
---
# Help Page Removed
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-infinite
This AdapTable Help Page has been deprecated.
---
# Help Page Removed
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-overview
This AdapTable Help Page has been deprecated.
---
# Server-Side Row Model - Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-calculated-columns
- Scalar (ie. single row) Calculated Columns work when using the Server-Side Row Model
- Aggregated (i.e. multi row) Calculated Columns require the calculated to be performed on the server
[Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) can work automatically when using AG Grid's Server-Side Row Model.
However this does depend on the complexity of the Calculation:
### Standard Calculated Columns
Standard Calculated Columns operate as normal in the Server-Side Row Model.
This is because they use [Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) which operate on a **single** row and are evalated as the row is rendered.
### Aggregated Calculated Columns
The more complex type of Calculated Columns ([Aggregated](https://www.adaptabletools.com/docs/handbook-calculated-column-aggregated/index.md) , [Cumulative](https://www.adaptabletools.com/docs/handbook-calculated-column-cumulative/index.md) and [Quantile](https://www.adaptabletools.com/docs/handbook-calculated-column-quantile/index.md)) **do not work** out of the box when using the Server-Side Row Model.
This is because they use [Aggregated Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) which work on **multiple** rows, and not all will be present on the client.
When this is the case, you will need to [evaluate the Expression on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) and return the value to AdapTable to render.
**Example: SSRM - Calculated Columns**
Server-Side Row Model: Calculated Columns
- This demo includes 3 Calculated Columns - `Total`, `Most`, `Points`
- All are standard (i.e. single-row) Calculated Columns and all work out of the box when using Server-Side Row Model
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM Calculated Columns',
initialState: {
Dashboard: {
PinnedToolbars: ['Layout'],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'totalMedals',
'mostMedals',
'points',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'totalMedals',
Query: {
ScalarExpression: '[gold] + [silver] + [bronze] ',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
Resizable: true,
Sortable: true,
},
FriendlyName: 'Total',
},
{
ColumnId: 'mostMedals',
Query: {
ScalarExpression:
'max([gold], [silver],[bronze]) = [gold] ? "Gold" : max([gold], [silver],[bronze]) = [silver] ? "Silver": "Bronze"',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
Resizable: true,
Sortable: true,
},
FriendlyName: 'Most',
},
{
ColumnId: 'points',
Query: {
ScalarExpression: '([gold] * 3) + ([silver] * 2) + ([bronze] * 1)',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
Resizable: true,
Sortable: true,
},
FriendlyName: 'Points',
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef, ColGroupDef} from 'ag-grid-enterprise';
export const columnDefs: (ColDef | ColGroupDef)[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
headerName: 'Medals',
marryChildren: true,
children: [
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'totalMedals',
headerName: 'Total',
type: ['calculatedColumn'],
cellDataType: 'number',
},
{
field: 'mostMedals',
headerName: 'Most',
type: ['calculatedColumn'],
cellDataType: 'text',
},
{
field: 'points',
headerName: 'Points',
type: ['calculatedColumn'],
cellDataType: 'number',
},
],
},
];
```
---
# Server-Side Row Model - Exporting
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-exporting
- Exporting reports works fine when using the Server-Side Row Model
- AdapTable enables developers to create report data on the server and pass to client for export
When running reports, AdapTable typically gathers the data required to run a Report, and then exports it to the specified destination.
But when using the Sever-Side Row Model, you will likely want to supply the data to be exported.
- AdapTable will then still take care of ensuring the data is sent to the appropriate destination
- Some reports - e.g. Selected Data - can be run fully on the client even when using Server-Side Row Model
This is done via the `processExport` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) - which takes the form of a function, which if provided, will be invoked when a Report is run.
The function receives a [`ProcessExportContext`](https://www.adaptabletools.com/docs/reference/processexportcontext.md) object, and returns (in the form of an [`ExportResultData`](https://www.adaptabletools.com/docs/reference/exportresultdata.md) object), the data for the Report which will be exported by AdapTable
See [Processing Reports](https://www.adaptabletools.com/docs/handbook-exporting-processing/index.md) for full information on how to process reports so they can be evaluated on the server
**Example: SSRM - Exporting**
Server-Side Row Model: Running Reports
- In this example we create a [Custom Report](https://www.adaptabletools.com/docs/handbook-exporting/index.md) called `US Golden Athletes` which exports all US Athletes who have won a Gold medal
- We provide and implementation for the `processExport` property in [Export Options](https://www.adaptabletools.com/docs/handbook-exporting-technical-reference/index.md) in order to gather the report data on the Server, and return it to AdapTable to be exported as needed
```ts
import {
AdaptableColumnBase,
AdaptableOptions,
BooleanFunctionName,
ModuleExpressionFunctionsContext,
ProcessExportContext,
Report,
ExportResultData,
ReportData,
SystemReportName,
} from '@adaptabletools/adaptable';
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
const REPORTS_HANDLED_CLIENT_SIDE: (SystemReportName | string)[] = [
'Current Layout',
'Selected Data',
];
interface RequestReportConfig {
report: Report;
reportColumns: AdaptableColumnBase[];
reportQueryAST?: any;
}
export async function handleExport(
context: ProcessExportContext
): Promise {
const {report, reportFormat} = context;
if (REPORTS_HANDLED_CLIENT_SIDE.includes(report.Name)) {
// these reports are client-side specific and will be handled by the default behaviour (which is to export the client-side data)
return true;
}
// everything else ('All Data' or any other custom Reports) will be handled server-side
const reportColumns =
report.Name === 'All Data'
? // sending an empty array will cause the server to use all columns
[]
: context.getReportColumns().filter(column => {
// for simplicity's sake, we're only going to filter out the special (synthetic) columns (Calculated, FreeText, Action)
// otherwise we would have to evaluate them on the server as well
return !context.adaptableApi.columnApi.isCalculatedColumn(
column.columnId
);
});
const reportConfig: RequestReportConfig = {
report,
reportColumns,
};
if (report.Query?.BooleanExpression) {
reportConfig.reportQueryAST =
context.adaptableApi.expressionApi.getASTForExpression(
report.Query.BooleanExpression
);
}
const serverSideResponse = await fetch(`${API_BASE}/report`, {
method: 'post',
body: JSON.stringify(reportConfig),
headers: {'Content-Type': 'application/json; charset=utf-8'},
});
const serverSideResultData: ExportResultData =
await serverSideResponse.json();
if (serverSideResultData.type !== 'json') {
console.log(
'In this showcase we always return JSON from the server, so this should never happen'
);
return serverSideResultData;
}
if (reportFormat === 'CSV') {
const csvContent = context.convertToCsv(serverSideResultData.data);
return {
type: 'csv',
data: csvContent,
};
}
if (reportFormat === 'Excel' || reportFormat === 'VisualExcel') {
const excelBLob = context.convertToExcel(serverSideResultData.data);
return {
type: 'excel',
data: excelBLob,
};
}
return serverSideResultData;
}
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM: Export',
exportOptions: {
processExport: handleExport,
systemReportNames: ['All Data', 'Current Layout'],
systemReportFormats: ['Excel', 'CSV', 'JSON'],
},
initialState: {
Dashboard: {
PinnedToolbars: ['Export'],
},
Theme: {
CurrentTheme: 'dark',
},
Export: {
CurrentReport: 'US Golden Athletes',
CurrentFormat: 'Excel',
Reports: [
{
Name: 'US Golden Athletes',
ReportColumnScope: 'ScopeColumns',
Scope: {
ColumnIds: ['athlete', 'gold', 'sport', 'year', 'country'],
},
ReportRowScope: 'ExpressionRows',
Query: {
BooleanExpression: '[country]="United States" AND [gold]>0',
},
},
],
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model - Filtering
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-filtering
- Both Column Filters and the Grid Filter need to be evaluated remotely when using Server-Side Row Model
- AdapTable provides functions that helps developers retrieve latest Filter state (to pass in to server)
- It also provides functions which can manage the complexity of both Predicates and Expressions
When using the Server-Side Row Model, AG Grid **will not perform any filtering**.
- [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md) works fully in Server-Side Row Model, both for data already in the Grid and new data as it is fetched
- However [Quick Search as Filter](https://www.adaptabletools.com/docs/handbook-quick-search-as-filter/index.md) will not work (unless you implement it yourself)
Instead AG Grid hands off those tasks to developer to perform on the server.
When using the Server-Side Row Model, it is the developer's responsibility to perform the actual filtering on the server
In practice this requires developers to provide server equivalents of 2 AdapTable filtering mechanisms:
- The Predicate-evaluation for [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md)
- An equivalent of [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) to evaluate the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md)
[AdaptableQL Server Evaluation](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md) provides instructions for managing complexity and scope of Predicates & Expressions
## Getting Filter State
When using the Server-Side Row Model, you need to fetch the current filter (and sort) state from AdapTable inside the `getRows` function.
The [Grid Filter Applied](https://www.adaptabletools.com/docs/handbook-grid-filter-technical-reference/index.md) and [Column Filter Applied](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) Events still fire, but are rarely subscribed to when using the SSRM
This is most easily done through the `getAdaptableFilterState` function in the [State API](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md#state-api) section of Adaptable API.
It returns an [`AdaptableFilterState`](https://www.adaptabletools.com/docs/reference/adaptablefilterstate.md) object defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [columnFilterDefs](https://www.adaptabletools.com/docs/reference/adaptablefilterstate.md#columnfilterdefs) | [`ColumnFilterDef`](https://www.adaptabletools.com/docs/reference/columnfilterdef.md)`[] \| undefined` | Column Filter definitions for currently applied Column Filters |
| [columnFilters](https://www.adaptabletools.com/docs/reference/adaptablefilterstate.md#columnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[] \| undefined` | Currently applied Column Filters |
| [gridFilter](https://www.adaptabletools.com/docs/reference/adaptablefilterstate.md#gridfilter) | `string \| undefined` | Current Grid Filter |
| [gridFilterAST](https://www.adaptabletools.com/docs/reference/adaptablefilterstate.md#gridfilterast) | `any` | AST for Current Grid Filter |
## Columns Filters
[Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) can still be applied when using the Server-Side Row Model, but instead of the Predicates being automatically evaluated by AdapTable, they are evaluated by developers on the server.
This can also include [Custom Filters](https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters/index.md), which will also be evaluated remotely in a bespoke implementation
### In Filter Values
AdapTable provides an [In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md), which allows users to select from a list of values for the Column.
By default, AdapTable simply lists all distinct values currently visible in the Grid's data source for the Column.
This is fine when using the Client-Side Row Model - as all data has been loaded - but can be unsatisfactory for the Server-Side Row Model, since it can result in a unnecessarily reduced list of values.
For this reason it is common when using the SSRM to implement the `customInFilterValues` property in [Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) in order to provide a fuller list of values.
- This is often coupled with [Suppressing Search in the In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md#suppressing-results-search) so that the search can be evaluated on the Server
- Another common practice is [turning on Manually Applying Filters](https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying/index.md) so just server invocation is made with all selected options
See [Guide to Using the In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md) for full details (and multiple demos)
### Limiting Predicates
By default AdapTable will provide every relevant System Predicate in each column.
This means a bespoke server implementation will need to translate **every** predicate into something meaningful.
Accordingly, AdapTable allows developer to [limit which System Predicates are available](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md#managing-system-predicates) in order to make the server implementation more manageable.
**Example: SSRM - Column Filtering**
Server-Side Row Model: Applying Column Filters
- The example shows how AdapTable Column Filters can still be used while using Server-Side Row Model:
- We get the current AdapTable Filter State and pass that to our mock server to evaluate
- We add a [Custom Filter Predicate](https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters/index.md) called `Superstar` with [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of `Athlete` column - and which also gets evaluated on the mock server (using rule: `gold > 2 OR (gold + silver + bronze) > 3`)
- We also provide an implementation for `customInFilterValues` to control which values are displayed in the In Filter - this is also handled on our mock server
- We turn on [Manually Applying Filters](https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying/index.md) so that only one call to the server made with all selections
- Run a Filter (e.g 3 in `Gold` column) and note how new data is fetched from the server that matches the Filter
- Run the `Superstar` Custom Filter on the Athlete column and note how our mock server evaluates it and returns the correct data
- Run the `In` Filter on the Athlete column and note how the server returns details of all athletes on the server (not just those already loaded)
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
DefaultPredicateFilterContext,
} from '@adaptabletools/adaptable';
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
export const getDistinctColumnValues = async (
columnId: string
): Promise<{value: string}[]> => {
const jsonResponse = await fetch(
`${API_BASE}/permitted-values?columnId=${columnId}`
);
return jsonResponse.json();
};
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Column Filtering',
predicateOptions: {
customPredicateDefs: [
// The custom predicate is handled on the server
// It returns `gold > 2 OR (gold + silver + bronze) > 3`;
{
id: 'superstar',
label: 'Superstar',
columnScope: {ColumnIds: ['athlete']},
moduleScope: ['columnFilter'],
handler: () => true,
},
],
},
filterOptions: {
customInFilterValues: async (context: CustomInFilterValuesContext) => {
const columnId = context.column.columnId;
const allColumnValues = await getDistinctColumnValues(columnId);
const inFilterValues = allColumnValues.map(item => ({
label: item.value,
value: item.value,
}));
return {
values: inFilterValues,
};
},
columnFilterOptions: {
manuallyApplyColumnFilter: true,
defaultTextColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'athlete' ? 'In' : 'Contains';
},
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
## Grid Filter
The [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) can still be applied when using the Server-Side Row Model, but instead of [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) evaluating the [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md), it will be perfomed by developers on the server.
- The Grid Filter can also include [Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) provided by developers
- These will also then need to be evaluated remotely in a bespoke implementation
### Limiting Expression Complexity
By default AdapTable will provide every [AdapTableQL Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) in the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md).
This means bespoke server implementations will need to translate **every** Expression into something meaningful.
Accordingly, AdapTable allows developers to [reduce Expression complexity](https://www.adaptabletools.com/docs/adaptable-ql-expression-managing/index.md) in 2 ways in order to make the server implementation more manageable:
- Limiting which **Expressions** are available (on a *per Module basis* if required)
- Limiting which **Columns** can be included in a Query / Expression
**Example: SSRM - Grid Filter**
Server-Side Row Model: Applying Grid Filter
- The example shows how the AdapTable Grid Filter can still be used while using Server-Side Row Model
- We include 2 [Named Queries ](https://www.adaptabletools.com/docs/handbook-named-queries/index.md) which are evaluated on our mock server (and accessible from dropdown at end of toolbar):
- `US Golds` - returns rows where USA has > 1 gold
- `European Athletes` - returns rows where country is in Europe (and uses a [Custom Boolean Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md), `FROM_EUROPE`, that is also evaluated on our mock server)
- We have provided a reduced set of [AdapTableQL Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) (for Grid Filter only) to make translating Expressions on the Server easier:
- We pass a small, reduced, set of `systemBooleanFunctions` to [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md)
- For all the other types of Expression Functions we only allow `COL` (which references a column) to be used
```ts
import {
AdaptableOptions,
BooleanFunctionName,
CustomInFilterValuesContext,
ModuleExpressionFunctionsContext,
} from '@adaptabletools/adaptable';
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
const supportedQueryBooleanOperators: BooleanFunctionName[] = [
'EQ',
'NEQ',
'GT',
'LT',
'GTE',
'LTE',
'AND',
'OR',
'NOT',
'BETWEEN',
'IN',
'CONTAINS',
'STARTS_WITH',
'ENDS_WITH',
];
export const getDistinctColumnValues = async (columnId: string) => {
const jsonResponse = await fetch(
`${API_BASE}/permitted-values?columnId=${columnId}`
);
return jsonResponse.json();
};
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Grid Filtering',
expressionOptions: {
moduleExpressionFunctions: (context: ModuleExpressionFunctionsContext) => {
if (context.module === 'GridFilter') {
return {
systemBooleanFunctions: supportedQueryBooleanOperators,
systemScalarFunctions: ['COL', 'IS_BLANK'],
customBooleanFunctions: {
FROM_EUROPE: {
// handled on the server
handler: () => true,
category: 'Custom',
isPredicate: true,
returnType: 'boolean',
description: 'Returns true if the country is from Europe',
signatures: ['FROM_EUROPE([country]'],
},
},
systemAggregatedBooleanFunctions: ['COL'],
systemAggregatedScalarFunctions: ['COL'],
systemObservableFunctions: ['COL'],
};
}
return;
},
},
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
const columnId = context.column.columnId;
return getDistinctColumnValues(columnId);
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['GridFilter', 'SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
NamedQuery: {
NamedQueries: [
{
Name: 'US Golds',
BooleanExpression: '[country]="United States" AND [gold] > 1',
},
{
Name: 'European Athletes',
BooleanExpression: 'FROM_EUROPE([country])',
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
Quick Search - to move
### How Does Quick Search Work?
Behind the scenes, AdapTable creates 2 objects to ensure matching search cells are correctly highlighted:
1. A bespoke CSS Style - updated whenever the [Quick Search Highlight Style](#defining-highlight-style) is set or changed
2. An [AG Grid Cell Style](https://www.ag-grid.com/javascript-data-grid/cell-styles/#cell-style) for every column - invoked each time the cell is rendered and which outputs the CSS Style if the Predicate returns true
There is a 350ms debounce to enable typing at normal speed typing before search is performed
---
# Server-Side Row Model - Formatting & Styling
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-formatting
- Column Formats, Styles and Conditional Styles operatre normally with the Server-Side Row Model
Column Formats, Styles and Styled Columns all work fully when using the Server-Side Row Model.
They are evaluated in real-time as a cell comes into view.
**Example: SSRM - Formatting Columns**
Server-Side Row Model: Styling and Formatting
- This demo shows styling and formatting applied when using Server-Side Row Model; it contains:
- a [Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) for numeric columns to align to right
- a [Style](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) for the `Athlete` column of bold and italic
- a [Column Formatting Condition](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md): rows with more than 1 Swimming Gold medal are blue with white font
- 3 [Gradient Styles](https://www.adaptabletools.com/docs/handbook-styled-column-gradient/index.md) - applied to `Gold`, `Silver` and `Bronze` coloured according to their name where they have values
- Scroll vertically and note as that new data is loaded into the grid, it is automatically styled
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Formatting',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'StyledColumn', 'SettingsPanel'],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-number',
Scope: {
DataTypes: ['number'],
},
Style: {
Alignment: 'Right',
},
},
{
Name: 'formatColumn-athlete',
Scope: {
ColumnIds: ['athlete'],
},
Style: {
FontWeight: 'Bold',
FontStyle: 'Italic',
},
},
{
Name: 'style-all',
Scope: {All: true},
Style: {
BackColor: '#87cefa',
ForeColor: '#ffffff',
},
Rule: {BooleanExpression: '[gold] > 1 AND [sport]="Swimming" '},
},
],
},
StyledColumn: {
StyledColumns: [
{
Name: 'gold Gradient',
ColumnId: 'gold',
GradientStyle: {
CellRanges: [{Min: 0, Max: 10, Color: '#ffee2e'}],
},
},
{
Name: 'bronze Gradient',
ColumnId: 'bronze',
GradientStyle: {
CellRanges: [{Min: 0, Max: 10, Color: '#ff9500'}],
},
},
{
Name: 'silver Gradient',
ColumnId: 'silver',
GradientStyle: {
CellRanges: [{Min: 0, Max: 10, Color: '#d3d3d3'}],
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model - Row Grouping
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-grouping
- Row Grouping is available in AdapTable when using the Server-Side Row Model
- The data needs to be grouped on the server and passed to the client to display
AdapTable fully supports Row Grouping when using the Server Side Row Model.
Nothing additional needs to be added, on the AdapTable side, to that which is provided in AG Grid's Server-Side architecture.
In other words the `rowGroupCols` and `groupKeys` props in `IServerSideGetRowsParams` are sufficient on their own
**Example: SSRM - Row Grouping**
Server-Side Row Model: Row Grouping
- This example show a grid using Server-Side where were group on the `Athlete` Column
- The grouping is evaluated on the Server and sent to the client to be rendered
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Grouping',
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['Layout', 'SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'Single Group Layout',
Layouts: [
{
Name: 'Single Group Layout',
TableColumns: [
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
RowGroupedColumns: ['athlete'],
ColumnSizing: {
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
{
Name: 'Multi Group Layout',
TableColumns: ['gold', 'silver', 'bronze', 'sport', 'year'],
RowGroupedColumns: ['country', 'athlete'],
RowGroupDisplayType: 'multi',
ColumnSizing: {
bronze: {Width: 100},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview
- Adaptable fully supports AG Grid's [Server-Side Row Model](https://www.ag-grid.com/javascript-grid-server-side-model/) (SSRM)
- It provides functions to help the bespoke filtering and sorting which needs to be handed on the server
AG Grid provides a [Server-Side Row Model](https://www.ag-grid.com/javascript-grid-server-side-model/) option, designed for very large data requirements.
The stated purpose of the Server-Side Row Model is to:
allow applications to work with very large datasets by delegating grid operations such as grouping, sorting and pivoting to the server. The data is then lazy loaded from the server in blocks as the user browses through the data.
The Server-Side Row Model is incredibly powerful, enabling huge amounts of data to be viewed in the Grid without overwehelming browser memory and other resources.
## Limitations
However the Server-Side Row Model does come with some important limitations which require a large amount of extra, bespoke, development.
The key limitations are that AG Grid (and AdapTable) **will not automatically perform** these Grid actions:
- filtering
- row grouping
- sorting
- pivoting
Instead it will hand off those tasks to the developer to perform on the server.
In many advanced use cases these limitations are unavoidable, and the SSRM remains the appropriate choice.
But we encounter many users who used the Server-Side Row Model when it was not needed, and the additional complexity of the solution outweighed any benefits.
- Only use the Server-Side Row Module if you have more than 200,000 records and absolutely require it
- Many of our clients tell us they ended up regretting the decision to use the Server-Side Row Model
Modern browsers are very powerful and AG Grid has excellent virtualisation; equally AdapTable is fast and performant and provides a huge range of out of the box features.
- AdapTable offers **DataSets** (via the [DataSet Module](https://www.adaptabletools.com/docs/handbook-data-sets/index.md)) for this very reason
- It allows you still to provide very large data while continuing to enjoy the benefits of the Client Side Row Model
## AG Grid Implementation
The key to configuring the Server Side Row Model in AG Grid is to provide a bespoke DataSource that implements the `IServerSideDatasource` interface.
This contains a function called `getRows` which is invoked by AG Grid **each time** that data needs to be retrieved.
In other words, any time the Grid is filtered, sorted, grouped, pivoted etc.
### Avoiding Repeated getRows calls in Server-Side Row Model
By their very nature AdapTable Layouts are reactive to changes that take place in AG Grid.
AdapTable listens to changes in the Grid and updates the Layout to ensure that everything is kept in sync and available when the Grid next loads.
However that can cause a problem with Server-Side Row Model particularly when switching Layouts.
This is because each time AG Grid changes and the AdapTable Layout updates, a call is made to `getRows`.
This will result in repeated, unnecessary calls to the server to fetch the same data.
For that reason we recommend memoising the call (or using a similar technique) so that data is not fetched unless something has changed.
The function receives a params object of type `IServerSideGetRowsParams`, which contains a number of properties of which the 2 most important are:
- **request** (of type `IServerSideGetRowsRequest`) – containing details of the current grouping, sorting, filtering and pivoting in the Grid
- **success** - the callback used when data is successfully retrieved from the server, passing it on to the grid
## AdapTable Implementation
The AG Grid implementation described above is fully supported in AdapTable, and most of the code in a `getRows` implementation is unchanged when using AdapTable.
For example, the row grouping, aggregation and pivoting properties in the `IServerSideGetRowsRequest` object sent by AG Grid can be left unchanged and passed in to any bespoke server implementation.
However there are 2 areas where AdapTable users will likely want to supplement the data provided by AG Grid:
- **filtering** - the `filterModel` prop in `IServerSideGetRowsRequest` does not take account of AdapTable's [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) (which use [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md)) and [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) (which leverages [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md))
- **sorting** - the the `sortModel` prop in `IServerSideGetRowsRequest` might need to be supplemented by any AdapTable [Custom Sorts](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md)
- AdapTable supports this via 2 functions provided in the [State API](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md#state-api) section of Adaptable API
- `getAdaptableFilterState` and `getAdaptableSortState` return details of AdapTable's current filtering and sorting
## Examples
The example below (and all other examples in this section) shows AdapTable with an AG Grid instance that is using the Server-Side Row Model.
All the examples share similar code which:
- implements the `IServerSideDatasource` interface with a `getRows` function that adds filtering and custom sorting (leveraging the 2 functions described above)
- contains a rough and ready mock server implementation (using SQL – [source code here](https://github.com/AdaptableTools/showcase-server-side-row-model/blob/master/server/SqlService.ts)) which mimics what is required on the server
- uses the same data which AG Grid uses for its [nodejs documentation](https://www.ag-grid.com/react-data-grid/server-side-operations-nodejs/)
The code used in these examles is for reference purposes only - please note that it is **not** production ready!
See the [standalone version](https://serverside-demo.adaptabletools.com/) of this demo (with full [source code](https://github.com/AdaptableTools/showcase-server-side-row-model)) which provides more detailed notes
**Example: Server-Side Row Model**
Server-Side Row Model: Full Demo
- The example shows AdapTable using the Server-Side Row Model (based off this example)
- It contains a number of server-related features, which are explained in more detail in other pages in this section, including:
- Filtering
- Evaluating Expressions
- Exporting
- Pivoting
- Sorting
- Formatting and Styling
- Row Grouping
- Note: Each time we retrieve data, apply a filter or sort the Grid, we output the SQl as a [System Status Message](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
- Apply a Filter (e.g. type in 4 into the Gold Column Filter Bar) and see how the data is refetched
- Open the System Status Popup (via `Configure` button) to see all the messages that have been sent - click the ellipsis to see the full SQL sent
```ts
import {
AdaptableOptions,
BooleanFunctionName,
CustomInFilterValuesContext,
DefaultPredicateFilterContext,
ModuleExpressionFunctionsContext,
} from '@adaptabletools/adaptable';
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
const supportedQueryBooleanOperators: BooleanFunctionName[] = [
'EQ',
'NEQ',
'GT',
'LT',
'GTE',
'LTE',
'AND',
'OR',
'NOT',
'BETWEEN',
'IN',
'CONTAINS',
'STARTS_WITH',
'ENDS_WITH',
];
export const getDistinctColumnValues = async (columnId: string) => {
const jsonResponse = await fetch(
`${API_BASE}/permitted-values?columnId=${columnId}`
);
return jsonResponse.json();
};
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Server-Side Row Model',
predicateOptions: {
customPredicateDefs: [
// The custom predicate is handled on the server : return `gold > 3 OR (gold + silver + bronze) > 3`;
{
id: 'superstar',
label: 'Superstar',
columnScope: {ColumnIds: ['athlete']},
moduleScope: ['columnFilter'],
handler: () => true,
},
],
},
expressionOptions: {
moduleExpressionFunctions: (context: ModuleExpressionFunctionsContext) => {
if (context.module === 'GridFilter') {
return {
systemBooleanFunctions: supportedQueryBooleanOperators,
systemScalarFunctions: ['COL', 'IS_BLANK'],
customBooleanFunctions: {
FROM_EUROPE: {
// handled on the server
handler: () => null,
returnType: 'boolean',
description: 'Returns true if the athlete is from Europe',
signatures: ['FROM_EUROPE'],
},
},
systemAggregatedBooleanFunctions: ['COL'],
systemAggregatedScalarFunctions: ['COL'],
systemObservableFunctions: ['COL'],
};
}
return;
},
},
filterOptions: {
customInFilterValues: async (context: CustomInFilterValuesContext) => {
const columnId = context.column.columnId;
const allColumnValues = await getDistinctColumnValues(columnId);
const inFilterValues = allColumnValues.map((item: any) => ({
label: item.value,
value: item.value,
}));
return {
values: inFilterValues,
};
},
columnFilterOptions: {
manuallyApplyColumnFilter: true,
defaultTextColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'athlete' ? 'In' : 'Contains';
},
},
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['GridFilter', 'SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
NamedQuery: {
NamedQueries: [
{
Name: 'US Golds',
BooleanExpression: '[country]="United States" AND [gold] > 1',
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model - Pivoting
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-pivoting
- Pivoting is available in AdapTable when using the Server-Side Row Model
- The data needs to be pivoted on the server and passed to the client to display
- Pivot result columns are created dynamically from the server response
AdapTable fully supports Pivoting when using the Server Side Row Model.
Nothing additional needs to be added, on the AdapTable side, to that which is provided in AG Grid's Server-Side architecture.
After each `getRows` response you typically build AG Grid **pivot result columns** from the fields the server returns (see `pivotResultColumns.ts` in the demo).
**Example: SSRM - Pivoting**
Server-Side Row Model: Pivoting
- Uses the public athletes mock server (`data.adaptable.dev`) to pivot on the server and return rows + `pivotFields`
- Switch Layouts in the Dashboard toolbar to compare patterns:
- **Year Pivot** — group by `Country`, pivot on `Year`, sum `Gold` (dynamic year columns)
- **Multi-Value Pivot** — same pivot with `Gold` / `Silver` / `Bronze` under each year group
- **Multi-Group Pivot** — group by `Country` then `Sport`, pivot on `Year` (expand a country to drill down)
- **Agg-Only Pivot** — Pivot Sum style: group by `Country`, sum medals, **no** `PivotColumns` (empty array)
- Pivot result columns are rebuilt whenever the server returns a new `pivotFields` set
- Start on **Year Pivot** and note the dynamic year columns
- Switch to **Multi-Value Pivot** and expand a year header to see gold / silver / bronze
- Switch to **Multi-Group Pivot**, expand a country, and see sports as the next group level
- Switch to **Agg-Only Pivot** for medal totals with pivot mode on but no year columns
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Pivoting',
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['Layout', 'SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'Year Pivot',
Layouts: [
// Classic SSRM pivot: group → pivot → one aggregation (dynamic year columns)
{
Name: 'Year Pivot',
PivotColumns: ['year'],
PivotGroupedColumns: ['country'],
PivotAggregationColumns: [
{
ColumnId: 'gold',
AggFunc: 'sum',
},
],
},
// Same pivot, multiple value columns → year groups with gold/silver/bronze children
{
Name: 'Multi-Value Pivot',
PivotColumns: ['year'],
PivotGroupedColumns: ['country'],
PivotAggregationColumns: [
{ColumnId: 'gold', AggFunc: 'sum'},
{ColumnId: 'silver', AggFunc: 'sum'},
{ColumnId: 'bronze', AggFunc: 'sum'},
],
},
// Drill-down row groups + year pivot (expand a country to see sports)
{
Name: 'Multi-Group Pivot',
PivotColumns: ['year'],
PivotGroupedColumns: ['country', 'sport'],
RowGroupDisplayType: 'multi',
PivotAggregationColumns: [
{
ColumnId: 'gold',
AggFunc: 'sum',
},
],
},
// Pivot Sum style: group + aggregations, no pivot columns (empty PivotColumns).
// Equivalent of handbook "Pivot Sum Layout" — values show as Gold/Silver/Bronze.
{
Name: 'Agg-Only Pivot',
PivotColumns: [],
PivotGroupedColumns: ['country'],
SuppressAggFuncInHeader: true,
PivotAggregationColumns: [
{ColumnId: 'gold', AggFunc: 'sum'},
{ColumnId: 'silver', AggFunc: 'sum'},
{ColumnId: 'bronze', AggFunc: 'sum'},
],
ColumnSizing: {
gold: {Width: 100},
silver: {Width: 100},
bronze: {Width: 100},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
Layout,
} from '@adaptabletools/adaptable';
import {
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
import {applyPivotResultColumns, PivotFieldEntry} from './pivotResultColumns';
/**
* Agg-only / Pivot Sum layouts use pivot mode with an empty PivotColumns array.
* Leftover year (etc.) secondary columns must be cleared when switching here.
*/
function hasPivotColumns(layout: Layout): boolean {
return (
'PivotColumns' in layout &&
Array.isArray(layout.PivotColumns) &&
layout.PivotColumns.length > 0
);
}
function clearPivotResultColumnsIfPresent(agGridApi: GridApi): void {
if (agGridApi.getPivotResultColumns() != null) {
// Must pass null (not []): empty array keeps AG Grid in pivot-result mode.
agGridApi.setPivotResultColumns(null);
}
}
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
// Clear secondary pivot columns as soon as we leave a layout that uses them
// (table layout, or agg-only pivot with no PivotColumns).
adaptableApi.eventApi.on('LayoutChanged', info => {
if (info.actionName !== 'LAYOUT_SELECT') {
return;
}
const layout = adaptableApi.layoutApi.getCurrentLayout();
if (
!adaptableApi.layoutApi.isCurrentLayoutPivot() ||
!hasPivotColumns(layout)
) {
clearPivotResultColumnsIfPresent(agGridApi);
}
});
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// AG Grid request + AdapTable filters/sorts → mock athletes server
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Pivot layouts with pivot columns: build dynamic result columns from
// the server response. Agg-only pivot (no pivotFields): clear leftovers
// so Gold/Silver/Bronze value columns can show.
const pivotFields = response.pivotFields as
| PivotFieldEntry[]
| undefined;
if (pivotFields?.length) {
applyPivotResultColumns(pivotFields, params.api);
} else {
clearPivotResultColumnsIfPresent(params.api);
}
if (response.sql) {
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
}
})
.catch(() => {
params.fail();
});
},
};
}
```
```ts
import type {ColDef, ColGroupDef, GridApi} from 'ag-grid-enterprise';
/**
* Shape returned by the athletes mock server for each pivoted result field.
* Matches the showcase SSRM client (`AdaptableTools/showcase-server-side-row-model`).
*/
export interface PivotFieldEntry {
field: string;
pivotValues: Record;
valueColumn: string;
aggFunc: string;
}
/**
* Build AG Grid pivot result columns (with column groups when needed) from the
* mock server's `pivotFields`, and apply them to the grid.
*
* Replaces an older demo helper that treated each field as `{ year: 2000 }` and
* skipped updates once any result columns already existed.
*/
export function applyPivotResultColumns(
pivotFields: PivotFieldEntry[],
agGridApi: GridApi
): void {
const newFieldIds = pivotFields.map(f => f.field);
const existingCols = agGridApi.getPivotResultColumns();
if (existingCols?.length) {
const existingIds = existingCols.map(c => c.getColId());
if (
existingIds.length === newFieldIds.length &&
existingIds.every((id, i) => id === newFieldIds[i])
) {
return;
}
}
agGridApi.setPivotResultColumns(createPivotResultColumns(pivotFields));
}
export function createPivotResultColumns(
pivotFields: PivotFieldEntry[]
): (ColDef | ColGroupDef)[] {
if (!pivotFields.length) {
return [];
}
const uniqueValueCols = new Set(pivotFields.map(f => f.valueColumn));
const hasMultipleValueCols = uniqueValueCols.size > 1;
const pivotKeys = Object.keys(pivotFields[0].pivotValues);
const root: (ColDef | ColGroupDef)[] = [];
for (const pf of pivotFields) {
const allLevels = pivotKeys.map(k => String(pf.pivotValues[k]));
if (hasMultipleValueCols) {
// e.g. Year → gold / silver / bronze under each year group
insertIntoTree(root, allLevels, {
colId: pf.field,
headerName: pf.valueColumn,
field: pf.field,
filter: false,
cellDataType: 'number',
});
} else {
// Single value column: leaf header is the pivot value (e.g. "2008")
const groupLevels = allLevels.slice(0, -1);
const leafLabel = allLevels[allLevels.length - 1];
insertIntoTree(root, groupLevels, {
colId: pf.field,
headerName: leafLabel,
field: pf.field,
filter: false,
cellDataType: 'number',
});
}
}
return root;
}
function insertIntoTree(
siblings: (ColDef | ColGroupDef)[],
groupLevels: string[],
leafCol: ColDef,
parentPath = ''
): void {
if (groupLevels.length === 0) {
siblings.push(leafCol);
return;
}
const [current, ...rest] = groupLevels;
const groupId = parentPath ? `${parentPath}_${current}` : `pivot_${current}`;
let group = siblings.find(
(s): s is ColGroupDef => 'groupId' in s && s.groupId === groupId
);
if (!group) {
group = {groupId, headerName: current, children: []};
siblings.push(group);
}
insertIntoTree(group.children!, rest, leafCol, groupId);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
enablePivot: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
enablePivot: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model - Searching
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-searching
- Quick Search when using the Server-Side Row Model, using bespoke AdapTable functionality
- A few features (such as recyling results) are missing
When using the Sever-Side Row Model, you can still use the AdapTable [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md) functionality.
However, this uses bespoke searching functionality, rather than act as a wrapper around AG Grid Find (which is what happens in the Client-Side Row Model).
The reason for this is that AG Grid's Find does not work in the Server-Side Row Model
As a result, one of the features of Quick Search - the ability to "cycle" through matching cells - is not available.
Likewise only the [Cell Matching Style](https://www.adaptabletools.com/docs/handbook-quick-search-matching-styles/index.md) (and not the 2 Text Matching Styles) is used.
**Example: SSRM - Searching**
Server-Side Row Model: Applying Quick Search
- In this example we run a Quick Search on "mi" - and all matching cells are highlighted
- As we scroll down the grid and new data comes into view it is also highlighted
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM: Quick Search',
initialState: {
Dashboard: {
PinnedToolbars: ['Export'],
},
Theme: {
CurrentTheme: 'dark',
},
QuickSearch: {
QuickSearchText: 'mi',
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model - Sorting
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-sorting
- Column Sorting information is included by AG Grid in the request object sent to the server to enable server sorting
- If using Custom Sorts, this request object, will need to be updated accordingly
When using the Server-Side Row Model, AG Grid **will not perform any sorting**.
Instead AG Grid hands that off to developers to perform on the server.
This is done using the standard `getRows` function in the custom `IServerSideDatasource` implementation, which can access a `sortModel` object that provides details of the current sorting in the Grid.
- the `getRows` function receives a `params` prop of type `IServerSideGetRowsParams` containing a `request` prop
- this is of type `IServerSideGetRowsRequest`, which describes current grid state, and includes `sortModel`
**Example: SSRM - Sorting**
Server-Side Row Model: Applying Sorts
- This example has 2 columns with Sorting - `Gold` (Desc) and `Silver` (Desc)
- Our mock server picks up the sorting in the `sortModel` object and updates the SQL it creates accordingly (using "OrderBy")
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Custom Sorting',
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSorts: [
{
ColumnId: 'gold',
SortOrder: 'Desc',
},
{
ColumnId: 'silver',
SortOrder: 'Desc',
},
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
GridSortedInfo,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
## Custom Sorts
There is one potential "gotcha" when sorting with the Server-Side Row Model.
The `sortModel` object has details of all [Column Sorts](https://www.adaptabletools.com/docs/handbook-layouts-table-sorting/index.md) in the Grid, but **is not aware** of any [Custom Sorts](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md).
Accordingly, it might be necessary to supplement the sortModel with any active Custom Sorts.
- The useful `getAdaptableSortState` function in [State API](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-technical-reference/index.md#state-api) returns an [`AdaptableSortState`](https://www.adaptabletools.com/docs/reference/adaptablesortstate.md) object
- It contains details of all Custom Sort objects (and Custom Sort Comparers) used by currently sorted Columns
**Example: SSRM - Custom Sorting**
Server-Side Row Model: Applying Custom Sorts
- This example we sort the Grid via the `Sport` Column
- We have also added a Custom Sort for this column which orders it 'Tennis', 'Cycling', 'Gymnastics' (and then alphabetically)
- We updated the Request we send to our mock server with this new Sort - which is then acted upon by the mock server and reflected in the data it sends back
- Scroll down the grid and notice how the Sport column is sorted using the Custom Sort
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM - Sorting',
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['SystemStatus'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
CustomSort: {
CustomSorts: [
{
Name: 'customSort-sport',
ColumnId: 'sport',
SortedValues: ['Tennis', 'Cycling', 'Gymnastics'],
},
],
},
Layout: {
CurrentLayout: 'SSRM Layout',
Layouts: [
{
Name: 'SSRM Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSorts: [
{
ColumnId: 'sport',
SortOrder: 'Asc',
},
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
GridSortedInfo,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Server-Side Row Model - Managing Data
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-server-updating
- AG Grid rows can be added, updated and deleted through AdapTable API methods when using the Server-Side Row Model
- These functions will, in turn, invoke the relevant AG Grid functions
The Server-Side Row Model adds and updates rows using the same Grid API row management functions as when using the Client Side Row Model, namely:
- `addGridData` – to [add Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-add/index.md)
- `updateGridData` - to [update Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-update/index.md)
- `deleteGridData` - to [delete Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-delete/index.md)
AdapTable, in turn, invokes the AG Grid `applyServerSideTransaction` or `applyServerSideTransactionAsync` functions as appropriate.
You can also use the `setCellValue` and `setCellValues` in Grid API to update individual cells, but this is rarely done
## Updating Rows
**Example: SSRM - Updating Rows**
Server-Side Row Model: Updating Data Rows
- This demo includes a Custom Dashboard Toolbar with 2 Buttons that call Grid API methods:
- *Update First Row* - updates the first row using `updateGridData`
- *Update Second Row* - updates `Gold` and `Bronze` columns in second row using `setCallValue`
- We leverage [Cell Flashing](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) to make it easy to see which cells have changed
```ts
import {
AdaptableButton,
AdaptableOptions,
CellUpdateRequest,
CustomToolbarButtonContext,
DataUpdateConfig,
} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM Update Row Data',
dashboardOptions: {
customToolbars: [
{
name: 'actions',
title: 'Actions',
toolbarButtons: [
{
label: 'Update First Row',
buttonStyle: {
tone: 'none',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const firstnode =
context.adaptableApi.gridApi.getFirstDisplayedRowNode();
if (firstnode) {
const pk =
context.adaptableApi.gridApi.getPrimaryKeyValueForRowNode(
firstnode
);
const firstRow = {
age: 23,
athlete: 'Michael Phelps',
bronze: 0,
country: 'United States',
country_group: 'U',
date: '24/08/2008',
gold: 7,
id: pk,
silver: 3,
sport: 'Swimming',
total: 8,
year: 2008,
};
const config: DataUpdateConfig = {
runAsync: true,
};
context.adaptableApi.gridApi.updateGridData([firstRow], config);
}
},
},
{
label: 'Update Second Row',
buttonStyle: {
tone: 'none',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const secondNode =
context.adaptableApi.gridApi.getRowNodeForIndex(1);
if (secondNode) {
const pk =
context.adaptableApi.gridApi.getPrimaryKeyValueForRowNode(
secondNode
);
const cellUpdateRequestGold: CellUpdateRequest = {
primaryKeyValue: pk,
newValue: 5,
columnId: 'gold',
};
const cellUpdateRequestBronze: CellUpdateRequest = {
primaryKeyValue: pk,
newValue: 3,
columnId: 'bronze',
};
context.adaptableApi.gridApi.setCellValues([
cellUpdateRequestGold,
cellUpdateRequestBronze,
]);
}
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['actions'],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
FlashingCell: {
FlashingCellDefinitions: [
{
Name: 'flashingCell-numeric-anyChange',
Scope: {
All: true,
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
## Adding Rows
The `addGridData` function in Grid API will add new Rows to the Grid while using the Server-Side Row Model.
When adding data, include the `addIndex` property in the [`DataUpdateConfig`](https://www.adaptabletools.com/docs/reference/dataupdateconfig.md) object if the new row should be visible
**Example: SSRM - Adding Rows**
Server-Side Row Model: Adding Data Rows
- This demo includes a Custom Dashboard Toolbar with a Button which adds a new row at the top of the grid
- We added a `ROW_ADDED` [Observable Alert](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md) to tell the user the row was inserted
```ts
import {
AdaptableButton,
AdaptableOptions,
CustomToolbarButtonContext,
DataUpdateConfig,
} from '@adaptabletools/adaptable';
const newRowUId: string = 'xy254878-4c38-4624-98ba-67be41a3ca3a';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'SSRM Add Row Data',
dashboardOptions: {
customToolbars: [
{
name: 'actions',
title: 'Actions',
toolbarButtons: [
{
label: 'Add Row',
buttonStyle: {
tone: 'none',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const newRow = {
age: 55,
athlete: 'John Smith',
bronze: 0,
country: 'United States',
country_group: 'U',
date: '24/08/2008',
gold: 9,
id: newRowUId,
silver: 5,
sport: 'Swimming',
total: 8,
year: 2008,
};
const config: DataUpdateConfig = {
addIndex: 0,
runAsync: true,
};
context.adaptableApi.gridApi.addGridData([newRow], config);
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['actions', 'Alert'],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'athlete',
'gold',
'silver',
'bronze',
'country',
'sport',
'year',
],
ColumnSizing: {
athlete: {Width: 175},
bronze: {Width: 100},
country: {Width: 125},
gold: {Width: 100},
silver: {Width: 100},
sport: {Width: 175},
year: {Width: 115},
},
},
],
},
Alert: {
AlertDefinitions: [
{
Name: 'alert-Success-69',
Rule: {
ObservableExpression: 'ROW_ADDED()',
},
MessageType: 'Success',
MessageHeader: 'You added a row',
Scope: {
All: true,
},
AlertProperties: {
DisplayNotification: true,
HighlightRow: {
BackColor: 'Purple',
ForeColor: 'White',
},
},
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
AdaptableApi,
AdaptableFilterState,
} from '@adaptabletools/adaptable';
import {
ColDef,
GridApi,
IServerSideDatasource,
IServerSideGetRowsParams,
IServerSideGetRowsRequest,
} from 'ag-grid-enterprise';
export const onAdaptableReady = ({
adaptableApi,
agGridApi,
}: AdaptableReadyInfo) => {
agGridApi.setGridOption(
'serverSideDatasource',
createDataSource(adaptableApi)
);
};
const API_BASE: string = process.env.NEXT_PUBLIC_ATHLETES_API_URL!;
function createDataSource(adaptableApi: AdaptableApi): IServerSideDatasource {
return {
getRows(params: IServerSideGetRowsParams) {
const getRowsRequest: IServerSideGetRowsRequest = params.request;
// get current filters and sorts in AdapTable
const adaptableFilterState: AdaptableFilterState =
adaptableApi.stateApi.getAdaptableFilterState();
const adaptableSortState = adaptableApi.stateApi.getAdaptableSortState();
// enhance sortModel with custom order if present
const sortModel = getRowsRequest.sortModel.map(sort => {
const customSort = adaptableSortState.customSorts.find(
customSort => customSort.ColumnId === sort.colId
);
if (customSort) {
return {
...sort,
sortedValues: customSort.SortedValues,
};
}
return sort;
});
// send the AG Grid request to the mock server together with filter info
const request = {
...getRowsRequest,
sortModel,
adaptableFilters: adaptableFilterState.columnFilterDefs,
gridFilterAST: adaptableFilterState.gridFilterAST,
includeSQL: true,
};
console.log('request to server', request);
// populate the success callback with the data retrieved from the mock server
fetch(API_BASE, {
method: 'post',
body: JSON.stringify(request),
headers: {'Content-Type': 'application/json; charset=utf-8'},
})
.then(httpResponse => httpResponse.json())
.then(response => {
params.success({
rowData: response.rows,
rowCount: response.lastRow ?? 0,
});
// Update any pivot result columns as necessary
if (response.pivotFields?.length) {
addPivotColumnDefs(response, params.api);
} else {
if (!adaptableApi.layoutApi.isCurrentLayoutPivot()) {
if (params.api.getPivotResultColumns() != null) {
params.api.setPivotResultColumns(null);
}
}
}
// set a System Status message with the SQL that was generated
adaptableApi.systemStatusApi.setInfoSystemStatus(
`SQL: ${response.sql.slice(0, 40)}`,
response.sql
);
})
.catch(error => {
params.fail();
});
},
};
}
function addPivotColumnDefs(response: any, agGridApi: GridApi) {
const existingPivotColDefs = agGridApi.getPivotResultColumns();
if (existingPivotColDefs && existingPivotColDefs.length > 0) {
return;
}
const pivotColDefs: ColDef[] = response.pivotFields.map(function (
field: any,
index: number
) {
const [_key, value] = Object.entries(field)[0];
const valueStr = `${value}`;
return {
headerName: valueStr,
field: valueStr,
filter: false,
colId: `${Date.now()}_${index}`,
cellDataType: 'number',
};
});
// supply pivot result columns to the grid
agGridApi.setPivotResultColumns(pivotColDefs);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
rowModelType: 'serverSide',
columnDefs: columnDefs,
sideBar: ['adaptable', 'columns', 'filters'],
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{field: 'id', hide: true, cellDataType: 'text'},
{
field: 'athlete',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'country',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'sport',
cellDataType: 'text',
enableRowGroup: true,
resizable: true,
},
{
field: 'year',
cellDataType: 'number',
enableRowGroup: true,
resizable: true,
},
{
field: 'gold',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'silver',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
{
field: 'bronze',
aggFunc: 'sum',
cellDataType: 'number',
enableValue: true,
resizable: true,
},
];
```
---
# Viewport Row Model
Canonical page: https://www.adaptabletools.com/docs/dev-guide-row-models-viewport
- The Viewport Role Model is one of the 3 server-based Row Models provided by AG Grid
- The server will provide data for exactly those rows currently viewable by the User
- This can be useful when updating very large live datastreams
- This comes at a price - many important features in AG Grid (and AdapTable) are missing
- However (as with [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md)) AdapTable provides many features to help with remote searching
AG Grid provides a [Viewport Row Model](https://www.ag-grid.com/javascript-data-grid/viewport/) option, used in very specific (and rare) use cases.
As described in the AG Grid documentation, the purpose of the Viewport Row Model is to:
show a 'window' of data in your client. Typically all the data will reside on the server and the server will know what data is displayed in the client. This is again useful for the server to push changes out to the client as it knows what data is currently displayed.
- We don't recommend the Vieport Row Model: its benefits rarely outweigh the many accompanying complications
- AG Grid also recommend using the more powerful Server-Side Row Model. They advise:
"Don't use Viewport Row Model unless you understand what advantages it offers and whether or not you need them. We find many of our users are using Viewport Row Model when they don't need to and end up with unnecessarily complicated applications as a result."
## Limitations
Using the Viewport Row Model comes at a significant cost as many features in AG Grid are not available.
These include many commonly used Grid elements such as:
- Filtering
- Grouping
- Pivoting
- Lazy Loading
- Aggregations
- Transaction Updates (sync & async)
All of these - with the exception of filtering - **are** available in the Server-Side Row Model
- See the full list of features unavailable in the Viewport Row Model in [AG Grid's Row Model Comparisons Table](https://www.ag-grid.com/javascript-data-grid/row-models/#row-model-comparisons)
## Filtering
As noted above, when using the Viewport Row Model, AG Grid **will not perform any filtering**.
Instead it will hand off those tasks to the server to perform.
This means that it is the developer's responsibility to perform the actual filtering on the server.
---
# AdapTable Performance
Canonical page: https://www.adaptabletools.com/docs/dev-guide-support-adaptable-performance
- AdapTable is designed to work in even the most demanding data environments
- This page demonstrates some ways of ensure AdapTable maintains good peformance even when using 'Big Data'
## Big Data
AdapTable is designed to work seamlessly with very large data sets.
- For grids with fewer than 100,000 rows we recommend using the Client-Side Row Model
- For larger grids the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) is required - also supported by AdapTable.
**Example: Displaying Big Data**
How AdapTable can handle very big data
- This demo loads **100,000** rows (and 20 columns)
- We have deliberately added very few styles or formats to allow you to add your own objects and test performance
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Big Data',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
// provide custom implementation for In filter to show count of each value
let returnvalues = context.defaultValues
.filter((info: InFilterValueInfo) => info)
.map(info => {
return {
value: info.value,
label: `${info.label} (${info.count})`,
};
});
return {values: returnvalues};
},
},
initialState: {
Dashboard: {
ModuleButtons: ['SettingsPanel'],
},
Layout: {
CurrentLayout: 'Table Layout',
Layouts: [
{
Name: 'Table Layout',
TableColumns: [
'id',
'prodName',
'company',
'price',
'amount',
'currency',
'orderDate',
'dueDate',
'lastName',
'firstName',
'origin',
'toAddress',
'invoiceNum',
'accountNum',
'department',
],
AutoSizeColumns: true,
},
{
Name: 'Grouped Layout',
TableColumns: [
'id',
'company',
'price',
'amount',
'currency',
'orderDate',
'dueDate',
'lastName',
'firstName',
'origin',
'toAddress',
'invoiceNum',
'accountNum',
'department',
],
AutoSizeColumns: true,
RowGroupedColumns: ['prodName'],
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = async ({adaptableApi}: AdaptableReadyInfo) => {
const data = await fetchData();
adaptableApi.gridApi.loadGridData(data);
adaptableApi.columnApi.autosizeAllColumns();
};
const API_BASE = process.env.NEXT_PUBLIC_ORDERS_API_URL;
async function fetchData() {
const response = await fetch(`${API_BASE}/100k`);
return response.json();
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
{
field: 'prodName',
headerName: 'Product Name',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'company',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'price',
cellDataType: 'number',
},
{
field: 'amount',
cellDataType: 'number',
},
{
field: 'currency',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'lastName',
headerName: 'Customer Last Name',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'firstName',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'origin',
headerName: 'Country of Origin',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'toAddress',
headerName: 'Shipping Address',
cellDataType: 'text',
},
{
field: 'orderDate',
cellDataType: 'date',
},
{
field: 'dueDate',
cellDataType: 'date',
},
{
field: 'invoiceNum',
headerName: 'Invoice Number',
cellDataType: 'number',
},
{
field: 'accountNum',
headerName: 'Account Number',
cellDataType: 'text',
},
{
field: 'department',
cellDataType: 'text',
enableRowGroup: true,
},
];
```
## Performance Tips
We leverage the excellent visualisation provided by AG Grid to ensure that styles are only applied to currently visible cells and rows.
Here a few tips to improve the performance of AdapTable:
- Use [Quick Search as Filter](https://www.adaptabletools.com/docs/handbook-quick-search-as-filter/index.md) very sparingly; but if used then look at leveraging AG Grid's [Quick Filter Cache](https://www.ag-grid.com/javascript-data-grid/filter-quick/#quick-filter-cache)
- Avoid using [Badge Styles](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) in cells which are updating regularly, and particularly if using [Flashing](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md)
**Example: AdapTable Performance**
How AdapTable performs when lots is happening
- This demo also loads **100,000** rows (and 20 columns)
- The `Price` and `Amount` columns are updated **400 times per second**
- We have added a number of style-related elements to the Grid:
- Custom [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) to the ticking `Price` and `Amount` columns
- A [Conditional Style](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) to the `Total Value` column (when > 80) - note that `Total Value` is a [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and also **updates in real time**
- A Row-based [Conditional Style](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) (Bold & Italic and Purple) where the `Product Name` is "Car" or "Bike"
- A [Date Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-date/index.md) for the `Order Date` and `Due Date` columns
- A [Percent Bar Style](https://www.adaptabletools.com/docs/handbook-styled-column-percent-bar/index.md) to the `Price Change` column
- A [Badge Style](https://www.adaptabletools.com/docs/handbook-styled-column-badge/index.md) to `Product Name` column (with different style based on cell value)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Performance',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
Layout: {
CurrentLayout: 'Table Layout',
Layouts: [
{
Name: 'Table Layout',
TableColumns: [
'prodName',
'company',
'price',
'priceChange',
'amount',
'total_value',
'orderDate',
'dueDate',
'lastName',
'firstName',
'origin',
'toAddress',
'invoiceNum',
'accountNum',
'department',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-total_value',
Scope: {
ColumnIds: ['total_value'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['80'],
},
],
},
RowScope: {
ExcludeSummaryRows: true,
},
Style: {
BackColor: '#99ffff',
},
},
{
Name: 'style-all',
Style: {
FontWeight: 'Bold',
FontStyle: 'Italic',
ForeColor: 'Purple',
},
Scope: {
All: true,
},
Rule: {
BooleanExpression: '[prodName] = "Car" OR [prodName] = "Bike" ',
},
},
{
Name: 'formatColumn-orderDate',
Scope: {
ColumnIds: ['orderDate', 'dueDate'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy',
},
},
},
],
},
StyledColumn: {
StyledColumns: [
{
Name: 'priceChange PercentBar',
ColumnId: 'priceChange',
PercentBarStyle: {
RangeValueType: 'Number',
CellRanges: [
{
Min: 0,
Max: 30,
Color: '#ff0000',
},
{
Min: 30,
Max: 50,
Color: '#ffa500',
},
{
Min: 50,
Max: 200,
Color: '#008000',
},
],
},
},
{
Name: 'prodName Badge',
ColumnId: 'prodName',
BadgeStyle: {
Badges: [
{
Predicate: {
PredicateId: 'In',
Inputs: ['Car', 'Bike'],
},
PillStyle: {
BackColor: 'DarkBlue',
ForeColor: 'white',
},
},
{
Predicate: {
PredicateId: 'In',
Inputs: ['Hat', 'Shoes', 'Gloves', 'Shirt', 'Pants'],
},
PillStyle: {
BackColor: 'Brown',
ForeColor: 'white',
},
},
{
PillStyle: {
BackColor: 'Purple',
ForeColor: 'white',
},
Predicate: {
PredicateId: 'In',
Inputs: ['Fish', 'Tuna'],
},
},
{
PillStyle: {
BackColor: 'Green',
ForeColor: 'white',
},
Predicate: {
PredicateId: 'In',
Inputs: ['Computer', 'Mouse', 'Keyboard'],
},
},
{
PillStyle: {
BackColor: 'Red',
ForeColor: 'white',
},
Predicate: {
PredicateId: 'In',
Inputs: ['Pizza', 'Salad', 'Cheese', 'Sausages'],
},
},
{
PillStyle: {
BackColor: 'Gray',
ForeColor: 'white',
},
},
],
},
},
],
},
FlashingCell: {
FlashingCellDefinitions: [
{
Name: 'flashingCell-amount-anyChange',
Scope: {
ColumnIds: ['price', 'amount'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
DownChangeStyle: {
BackColor: '#ff7591',
},
UpChangeStyle: {
BackColor: '#32cd32',
},
NeutralChangeStyle: {
BackColor: '#d3d3d3',
},
FlashDuration: 300,
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'total_value',
Query: {
ScalarExpression: '[price] * [amount]',
},
CalculatedColumnSettings: {
DataType: 'number',
},
FriendlyName: 'Total Value',
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo, AdaptableApi} from '@adaptabletools/adaptable';
import {IRowNode} from 'ag-grid-enterprise';
export const onAdaptableReady = async ({adaptableApi}: AdaptableReadyInfo) => {
const data = await fetchData();
adaptableApi.gridApi.loadGridData(data);
adaptableApi.columnApi.autosizeAllColumns();
setTimeout(() => {
randomlyUpdateData(adaptableApi);
}, 1000);
};
const API_BASE = process.env.NEXT_PUBLIC_ORDERS_API_URL;
async function fetchData() {
const response = await fetch(`${API_BASE}/100k`);
const data = await response.json();
return data.map((item: any) => ({...item, priceChange: 0}));
}
function randomlyUpdateData(api: AdaptableApi) {
setInterval(() => {
const visibleRows = api.agGridApi.getRenderedNodes();
if (!visibleRows) {
return;
}
const numberOfRowsToUpdate = 5;
for (let i = 0; i < numberOfRowsToUpdate; i++) {
const row = visibleRows[getRandomInt(-1, visibleRows.length - 1)];
if (row) {
updateRow(api, row);
}
}
}, 30);
}
function getRandomInt(min: number, max: number) {
return min + Math.ceil(Math.random() * (max + 1));
}
async function updateRow(api: AdaptableApi, row: IRowNode) {
const getDelta = (num: number): number => Math.ceil(0.2 * num);
const updateConfig = {runAsync: true};
const initialData = row.data;
if (!initialData) {
return;
}
const priceDelta = getDelta(initialData?.price);
const amountDelta = getDelta(initialData?.amount);
const newPrice = initialData.price + getRandomInt(-priceDelta, priceDelta);
const newAmount =
initialData.amount + getRandomInt(-amountDelta, amountDelta);
let newData = {
...initialData,
price: newPrice,
amount: newAmount,
priceChange: getRandomInt(0, 100),
};
await api.gridApi.updateGridData([newData], updateConfig);
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
editable: false,
},
{
field: 'prodName',
headerName: 'Product Name',
cellDataType: 'text',
},
{
field: 'company',
cellDataType: 'text',
},
{
field: 'price',
cellDataType: 'number',
},
{
field: 'priceChange',
cellDataType: 'number',
},
{
field: 'initialPrice',
cellDataType: 'number',
},
{
field: 'amount',
cellDataType: 'number',
},
{
field: 'currency',
cellDataType: 'text',
},
{
field: 'lastName',
headerName: 'Customer Last Name',
cellDataType: 'text',
},
{
field: 'firstName',
cellDataType: 'text',
},
{
field: 'origin',
headerName: 'Country of Origin',
cellDataType: 'text',
},
{
field: 'toAddress',
headerName: 'Shipping Address',
cellDataType: 'text',
},
{
field: 'orderDate',
cellDataType: 'date',
},
{
field: 'dueDate',
cellDataType: 'date',
},
{
field: 'orderDate',
cellDataType: 'date',
},
{
field: 'invoiceNum',
headerName: 'Invoice Number',
cellDataType: 'number',
},
{
field: 'accountNum',
headerName: 'Account Number',
cellDataType: 'text',
},
{
field: 'department',
cellDataType: 'text',
},
];
```
---
# Auditing User and Grid Activity
Canonical page: https://www.adaptabletools.com/docs/dev-guide-support-auditing
- There are numerous ways in AdapTable to audit Grid and user activity
- The Data Change history module shows a full view of all data changes
- Events for Adaptable State, Layout, Cell and Row changes can be subscribed to
- Cell and Row Change Alerts can be configured to fire as necessary
---
# Logging
Canonical page: https://www.adaptabletools.com/docs/dev-guide-support-logging
- Logging can be used by Support Teams to debug AdapTable
- There are 5 Types of Log Messages which development teams can configure as required
AdapTable logs 5 types of messages to the console as the application runs.
These messages will only be visible if you choose to make them so - see below for details.
The 5 types are:
- Error
- Warning
- Success
- Info
- Performance Metrics
AdapTable always logs **critical** messages which need to be seen - these require no developer action to be visible
## Making Messages Visible
To make logging visible you need to add a new local storage key-value pair.
This [guide by Chrome](https://developer.chrome.com/docs/devtools/storage/localstorage/#create) provides instructions on how to create local storage key-value pairs
To log **all** messages you need to do:
```
// hint: this may be a bit too noisy!
localStorage.debug = '*'
```
or alternatively, to log all message types for all AdapTable instances:
```
localStorage.debug = 'Adaptable:*'
```
## Setting Message Types
If you want a more granular approach, you can filter by message type or by AdapTable instance (or both) using the following pattern:
```
Adaptable::
```
- `` is the id of the AdapTable instance you want to log for (which was [set during initialisation](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md))
- `` is the type of message you want to log, can be one of:
- `error`: error messages
- `warn`: warning messages
- `success`: success messages
- `info`: info messages
- `perf`: performance metrics
Examples:
```
// log all messages for a specific AdapTable instance
localStorage.debug = 'Adaptable::*'
```
```
// log only error messages for all AdapTable instances
localStorage.debug = 'Adaptable:*:error'
```
```
// log only warn messages for a specific AdapTable instance
localStorage.debug = 'Adaptable::warn'
```
Message types are **not** additive; to see multiple message types, specify them all and separate by using a comma
```
// log error and warn messages for a specific AdapTable instance
localStorage.debug = 'Adaptable::error,Adaptable::warn'
```
```
// log error and perf messages for all AdapTable instances
localStorage.debug = 'Adaptable:*:error,Adaptable:*:perf'
```
## Layout Logging
AdapTable offers additional logging assistance for [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) as they are so intrinsic to how the tool works.
This can by enabled by setting:
```
localStorage.debug = 'LayoutManager:*'
```
This will log all changes related to a Layout: e.g. column visibility, sorting, row grouping, column resizing, pivoting, aggregations, pinning, switching the layout etc.
## Peformance Logging
Logging can be used to log performance metrics for certain operations.
See the [Guide to Profiling](https://www.adaptabletools.com/docs/dev-guide-support-profiling/index.md) for detailed information
---
# Monitoring Grid Activity
Canonical page: https://www.adaptabletools.com/docs/dev-guide-support-monitoring
- Many AdapTable features provide an overview of what is happening in the Grid. These include
- AdapTable Events which fire whenever anything happens in the Grid or in AdapTable State
- The Data Change History Monitor can be used to track data changes
- The State Management Panel facilitates monitoring of AdapTable State
- Data Change and Row Change Alerts can be configured
- The Grid Info Panel provides an over view of the current grid for runtime users
AdapTable provides a number of ways for Support Teams to monitor user's (and general Grid) activity:
- Listening to Adaptable State Changes
- Subscribing to other Adaptable Events, particularly Cell Changed and Row Changed
- Monitoring Data Changes
- Configuring Alerts to respond to cell and row changes
- Managing AdapTable State
- Using the Grid Info Monitor
- Some of these options (e.g. Events and Alerts) are typically mutually exclusive
- This allows each Support Team to choose the workflow that suits it best
## AdapTable State Changes
The [Adaptable State Changed Event](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md) provides a stream of all state changes.
All grid activity - every action, object change, mouse click etc. - can be listened to, and logged, as required.
## AdapTable Events
In addition, to State Changed, AdapTable provides a large number of other useful [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md) which can be used to monitor changes in the Grid, most notably:
| Event | When Fired |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| [Row Changed Event](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) | A Row has been added, deleted (or even updated) |
| [Layout Changed Event](https://www.adaptabletools.com/docs/handbook-layouts-monitoring/index.md) | A Layout changes (ie. columns, filters, sorts, groups, aggregations etc.) |
| [Cell Changed Event](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md) | Contents of a cell changes (whether direct edit or ticking data) |
| [Theme Selected](https://www.adaptabletools.com/docs/handbook-theming-technical-reference/index.md) | A Theme has been selected |
| [Data Imported](https://www.adaptabletools.com/docs/handbook-importing-technical-reference/index.md) | The Data Import wizard has finished |
## Data Change History
The [Data Change History Monitor](https://www.adaptabletools.com/docs/handbook-monitoring-data-change-history/index.md) will track all data changes in AG Grid cells.
The Monitor has many features including:
- track all changes or just edits or ticking data
- ability to add an `undo` button (or other action buttons)
- option to see all changes, or just last change, for a Cell
## State Management Panel
The [State Management Panel](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-management/index.md) facilitates monitoring AdapTable State.
It allows the user to
- Clear User State
- Load Initial State
- Export the current State, or the Initial State, to multiple destinations
## AdapTable Alerts
As an altenative to subscribing to Events, you can set up [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) to keep abreast of user activity.
There are 2 Alert types, in particular, which are relevant here:
| Alert | When Fired |
| ----------------------------------------------------------------------- | --------------------------------------------- |
| [Data Change](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) | The contents of a Cell has changed |
| [Row Change](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) | Rows have been added or removed from the Grid |
One advantage of Alerts is that you can configure Rules so the Alerts are only fired for some, rather than all, changes
## Grid Info Panel
The Grid Info Panel offers run-time full oversight of what is happening in AdapTable.
There is a companion [Column Info Panel](https://www.adaptabletools.com/docs/dev-guide-columns-column-info/index.md) which offers detailed information on each Column
The Grid Info Panel is, typically, the first Panel displayed in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) and contains 3 tabs:
- Grid Summary
- Grid State
- Grid Options
- Grid Info can also be opened via the `Grid Info` Menu Item in both the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) and [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md)
- The 2 Menus have an associated menu item `Column Info` which opens the [Column Info Panel](https://www.adaptabletools.com/docs/dev-guide-columns-column-info/index.md)
### Grid Summary
The Grid Summary tab provides basic information about the grid. This includes:
- Which [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) are applied
- If a [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md) is applied
- Which [Column Sorts](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) are active
- Row information - including counts of total, visible and selected rows
- Column information - counts of total and visible columns
- Special Column Information - any [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) or [FreeText](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) or [Action](https://www.adaptabletools.com/docs/handbook-action-column/index.md) Columns
- The AdapTable and AG Grid versions being used
You can [hide these entries](https://www.adaptabletools.com/docs/ui-tutorial-hiding-adaptable/index.md#hiding-adaptable-version) by setting `showAdapTableVersion` \ `showAgGridVersion` to _false_ in [User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md)
### Grid State
This section provides information about every [Adaptable Object](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects) which has been created.
It also contains buttons to edit / delete these Objects via the relevant wizard.
**Example: Grid Info Panel**
Using Grid Info to get overview of all AdapTable objects
- This demo illustrates the Grid Info section of the Settings Panel
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Grid Info',
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.gridApi.openGridInfoSettingsPanel();
};
```
### Grid Options
The Grid Options tab provides full - readonly - details of every property in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
The properties are displayed according to type.
It shows all the current property values, whether set as defaults by AdapTable or overriden by the User.
---
# Supporting AdapTable
Canonical page: https://www.adaptabletools.com/docs/dev-guide-support-overview
- Guides for Support Teams who are managing an application containing AdapTable
---
# Profiling
Canonical page: https://www.adaptabletools.com/docs/dev-guide-support-profiling
- AdapTable provides 2 very useful resources to help Support Teams profile AdapTable:
- It will provide performance metrics (by leveraging logging)
- It offers performance profiling (by leveraging the Chrome DevTools profiler)
AdapTable provides some very useful resources to help Support Teams profile AdapTable.
## Performance Metrics
AdapTable logs performance metrics for certain operations.
Consult the [Guide to Logging AdapTable Activity](https://www.adaptabletools.com/docs/dev-guide-support-logging/index.md) for full details on how AdapTable enables comprehensive logging
These are logged as `perf` messages.
Make sure to set the Browser's console level to `Verbose` to see these messages ([read instructions for using Chrome](https://developer.chrome.com/docs/devtools/console/log/#level))
```
// log all performance metrics for all AdapTable instances
localStorage.debug = 'Adaptable:*:perf'
```
```
// log all performance metrics for a specific AdapTable instance
localStorage.debug = 'Adaptable::perf'
```
The `perf` messages will look like this:
```
Adaptable:Trades:perf [BEGIN] - initializeAgGrid() +1ms
[...]
Adaptable:Trades:perf [END] - initializeAgGrid() (waitForAgGrid=TRUE) :: [delta +122ms] +1ms
```
The delta value (`[+122ms]`) is the time taken for the operation (`initializeAgGrid()`) to complete.
The last diff value (`+1ms`) is displayed for all messages and is the time spent between the previous message and the current one.
## Performance Profiling
Another way to profile performance in AdapTable is to use the Chrome DevTools profiler.
AdapTable will show up as a custom track in your recorded profile.
This is a very powerful tool which will give you a better sense of the timing for various operations.
It includes stacktraces and allows you to see the correlation between user actions, other browser events and the AdapTable instance.
### Chrome DevTools Profiler
To start a profiling operation, open your DevTools, go to the `Performance` tab and start recording.
In order to see the custom dev tracks for AdapTable, you have to enable them by setting the `adaptableProfileTracks` key to `"true"` in your `localStorage`:
```tsx
localStorage.adaptableProfileTracks = 'true'
```
This is the easiest way.
Another option would be to enable the debug channels for performance metrics, as already described above
```tsx
localStorage.debug = 'Adaptable:*:perf'
```
This will show you all AdapTable instances - each under the `AdapTable (:perf` channel.
For instance you have a 'BigData' AdapTable instance, then you will do:
```tsx
localStorage.debug = 'Adaptable:BigData:perf'
```
Or you can simply enable all debug channels:
```tsx
localStorage.debug = '*'
```
In this picture, you can see a recorded profile and how AdapTable displays its custom tracks.

In your recorded profiling traces, you can click various segments to get more info on the specific operation.
In the screenshot above, we selected the `'Apply table layout'` operation to get details on it.
Beyond timing (this one took 370ms), we have info on the Layout's Name, Columns, Row Grouping and other useful Layout properties.
### Available Tracks and Labels
Each profiled AdapTable instance will show up as a group, under the name `Adaptable (AdapTable React Vitest Template
- Tests typically interact with AdapTable through the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) once the [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) has fired
- This page covers the essentials; we are working on a fuller guide with worked examples for each test runner and framework wrapper
- If you have a specific testing question in the meantime, please [contact us](https://www.adaptabletools.com/support/adaptable-support)
## Choosing a Test Runner
AdapTable is a standard JavaScript / TypeScript library and works with every mainstream test runner
There is no AdapTable-specific test framework — pick whatever your application already uses.
The runners and tools known to work well include:
| Runner | Notes |
| --- | --- |
| **[Vitest](https://vitest.dev/)** | Fast and modern, drop-in compatible with the Jest API; the runner used in our public [React testing template](https://github.com/AdaptableTools/testing-template-vitest-adaptable-react-aggrid) |
| **[Jest](https://jestjs.io/)** | Widely used; works equally well for unit and integration tests against the Adaptable API |
| **[Playwright](https://playwright.dev/)** | Recommended for end-to-end tests where you want to drive AdapTable through the actual browser UI; this is what we use internally |
| **[Testing Library](https://testing-library.com/)** | Pairs cleanly with Vitest or Jest when rendering AdapTable inside a component test |
- Unit-style tests that drive AdapTable using [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) are the fastest, most reliable and easiest to maintain
- Reach for end-to-end browser tests only when you specifically need to exercise the UI surface
## Writing Tests Against AdapTable
A few practical things to know when authoring tests:
- **Adaptable initialises asynchronously.** `Adaptable.init` (vanilla) and the framework wrappers all expose AdapTable through the [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md). Wait for this event in your test setup before asserting on grid state or invoking API methods.
- **The [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) is the primary test surface.** Anything a user can do in the UI can be done programmatically through the API — applying Filters, switching Layouts, running Exports, editing cells, etc. — which makes assertions concise and avoids brittle DOM selectors.
- **Stub [State Persistence](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#remote-storage).** In tests you almost always want `stateOptions.persistState` and `stateOptions.loadState` to be no-ops (or return a fixed test fixture), so that tests are deterministic and isolated from any real backend.
- **Provide a deterministic `adaptableId`.** Different tests should use different IDs (or fully isolated state) to avoid cross-test pollution if you share a persistence layer.
- **Subscribe to the [Adaptable State Changed Event](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md)** when you need to assert that an action produced the expected state change without having to poll.
## Example
The [AdapTable React Vitest Template](https://github.com/AdaptableTools/testing-template-vitest-adaptable-react-aggrid) is a complete, runnable repository that shows:
- a minimal React + AG Grid + AdapTable setup
- a Vitest configuration that handles AdapTable's async initialisation
- example tests that wait for Adaptable Ready and then assert against the Adaptable API
Fork it as a starting point for your own test suite.
---
# Holiday Calendars
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-holiday-calendars
- AdapTable allows developers to provide custom Holiday Calendars
- These are used when evaluating System Predicates which reference Holidays
- Holidays can be provided either as a list of Dates or via a function
## Providing Holiday Calendars
AdapTable provides 4 Date-related [System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md) which reference Holidays:
- `NextWorkDay`
- `LastWorkDay`
- `WorkDay`
- `Holiday`
Each of these Predicates will take any bespoke Holidays into account during evaluation.
By default AdapTable will only count non-weekdays as Holidays.
- AdapTable has no internal knowledge of any Public Holidays - even major ones like New Year's Day
- It is the job of the developer to provide the custom holidays for each user
Holidays are provided using the `holidays` property in [`Calendar Options`](https://www.adaptabletools.com/docs/reference/calendaroptions.md).
### `holidays`
Holidays - used to determine Working Days
List of Holidays to use when evaluating Working-Day related Predicates.
As can be seen, the property allows the Holiday Dates to be supplied in 2 ways:
- as a list of Dates
- as a function which returns a list of Dates
### Providing a List of Holidays
The simplest way to provide Holidays is as a list of dates in ISO string format:
```ts {4,5}
// Set Christmas and New Year as Public Holidays
const adaptableOptions: AdaptableOptions = {
calendarOptions: {
holidays: ['2022-12-25', '2023-01-01'],
},
}
```
### Providing a Function
Alternatively a JavaScript function can be provided when using the `holidays` property.
This takes **precedence** over the list option
The function receives an object of type [`BaseContext`](https://www.adaptabletools.com/docs/reference/basecontext.md) and returns a list of Dates.
The function can be used like this:
```ts {3,4,5}
// Set Christmas and New Year as Public Holidays
const adaptableOptions: AdaptableOptions = {
calendarOptions: {
holidays: (baseContext: BaseContext) => {
return [new Date(2022, 11, 25), new Date(2023, 0, 1)]
},
},
}
```
**Example: Providing Custom Holidays**
Settings Holidays and Working Days in AdapTable
- This demo shows how to provide AdapTable with custom holidays
- We provide all dates between 22 December 2020 and 3 January 2021
- We provide 3 Holiday Dates: Christmas Day (25 Dec), Boxing Day (26 Dec) and New Years Day (1 Jan)
- We set the Layout to show the `WorkDay` Predicate, and the Column does not include the 3 holidays
### Expand to see Calendar definitions
```ts
calendarOptions: {
holidays: [
new Date(2020, 11, 24),
new Date(2020, 11, 25),
new Date(2021, 0, 1),
],
},
```
```ts
import {
SystemFilterPredicateIds,
SystemPredicatesContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {TradeInfo} from './rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'tradeId',
userName: 'Demo User',
adaptableId: 'Holiday Calendars',
predicateOptions: {
systemFilterPredicates: (context: SystemPredicatesContext) => {
return context.systemPredicateDefs
.map(filter => filter.id)
.filter(filterId => {
return ![
'Today',
'Yesterday',
'Tomorrow',
'ThisWeek',
'ThisMonth',
'ThisQuarter',
'ThisYear',
'InPast',
'InFuture',
].includes(filterId);
}) as SystemFilterPredicateIds;
},
},
calendarOptions: {
holidays: [
new Date(2020, 11, 24),
new Date(2020, 11, 25),
new Date(2021, 0, 1),
],
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Demo',
Toolbars: ['ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: ['tradeId', 'tradeDate'],
ColumnSizing: {
tradeId: {Width: 100},
tradeDate: {Width: 350},
},
ColumnFilters: [
{
ColumnId: 'tradeDate',
Predicates: [
{
PredicateId: 'WorkDay',
},
],
},
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-tradeDate',
Scope: {
ColumnIds: ['tradeDate'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'EEEE MMMM do yyyy',
},
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
import {TradeInfo} from './rowData';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
// adaptableApi.gridApi.setGridData(getGridData());
};
function getGridData(): TradeInfo[] {
let tradeInfo: TradeInfo[] = [];
tradeInfo.push({
tradeId: 1,
tradeDate: new Date(2022, 11, 22),
});
tradeInfo.push({
tradeId: 2,
tradeDate: new Date(2022, 11, 23),
});
tradeInfo.push({
tradeId: 3,
tradeDate: new Date(2022, 11, 24),
});
tradeInfo.push({
tradeId: 4,
tradeDate: new Date(2022, 11, 25),
});
tradeInfo.push({
tradeId: 5,
tradeDate: new Date(2022, 11, 26),
});
tradeInfo.push({
tradeId: 6,
tradeDate: new Date(2022, 11, 27),
});
return tradeInfo;
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
sortable: true,
filter: true,
floatingFilter: true,
enableRowGroup: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'tradeId',
cellDataType: 'number',
},
{
field: 'tradeDate',
cellDataType: 'date',
},
];
```
```ts
export interface TradeInfo {
tradeId: number;
tradeDate: Date;
}
export const rowData = [
{
tradeId: 1,
tradeDate: new Date(2020, 11, 22),
},
{
tradeId: 2,
tradeDate: new Date(2020, 11, 23),
},
{
tradeId: 3,
tradeDate: new Date(2020, 11, 24),
},
{
tradeId: 4,
tradeDate: new Date(2020, 11, 25),
},
{
tradeId: 5,
tradeDate: new Date(2020, 11, 26),
},
{
tradeId: 6,
tradeDate: new Date(2020, 11, 27),
},
{
tradeId: 7,
tradeDate: new Date(2020, 11, 28),
},
{
tradeId: 8,
tradeDate: new Date(2020, 11, 29),
},
{
tradeId: 9,
tradeDate: new Date(2020, 11, 30),
},
{
tradeId: 10,
tradeDate: new Date(2020, 11, 31),
},
{
tradeId: 11,
tradeDate: new Date(2021, 0, 1),
},
{
tradeId: 12,
tradeDate: new Date(2021, 0, 2),
},
{
tradeId: 13,
tradeDate: new Date(2021, 0, 3),
},
];
```
## Technical Reference
### Calendar Options
Calendar Section of Adaptable Options contains the `calendars` property:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [holidays](https://www.adaptabletools.com/docs/reference/calendaroptions.md#holidays) | `Date[] \| ((baseContext: `[`BaseContext`](https://www.adaptabletools.com/docs/reference/basecontext.md)`) => Date[] \| undefined)` | Holidays for current User | null |
### Calendar API
Calendar Section of Adaptable API contains functions relating to Calendars, Holidays and Working Days in AdapTable
| Method | Returns | Description |
| --- | --- | --- |
| [getNextWorkingDay()](https://www.adaptabletools.com/docs/reference/calendarapi.md#getnextworkingday) | `Date` | Returns the next Working Day |
| [getPreviousWorkingDay()](https://www.adaptabletools.com/docs/reference/calendarapi.md#getpreviousworkingday) | `Date` | Returns the previous Working Day |
| [isHoliday(dateToCheck)](https://www.adaptabletools.com/docs/reference/calendarapi.md#isholiday) | `boolean` | Checks if given data is a Holiday |
| [isSameDay(date1, date2)](https://www.adaptabletools.com/docs/reference/calendarapi.md#issameday) | `boolean` | Returns true if both Dates are the same, ignoring the time portions |
| [isToday(dateToCheck)](https://www.adaptabletools.com/docs/reference/calendarapi.md#istoday) | `boolean` | Returns true if the given date is today |
| [isTomorrow(dateToCheck)](https://www.adaptabletools.com/docs/reference/calendarapi.md#istomorrow) | `boolean` | Returns true if the given date is tomorrow |
| [isWorkingDay(dateToCheck)](https://www.adaptabletools.com/docs/reference/calendarapi.md#isworkingday) | `boolean` | Checks if given date is a Working Day |
| [isYesterday(dateToCheck)](https://www.adaptabletools.com/docs/reference/calendarapi.md#isyesterday) | `boolean` | Returns true if the given date is yesterday |
---
# Setting up Hotkeys
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-hotkeys
- This page show how it is possible to use Hotkeys in AdapTable
It is easy to set up 'Hot Key's in Adaptable - whereby you can define actions to be taken in reaction to a given set of keystrokes.
This can be accomplished in 2 ways:
- through a third party library (like Mousetrap)
- by listening to the native 'keydown' event
**Example: Hot Keys**
Using Hot Keys in AdapTable
- In this demo we have set 4 Hot Keys - 2 using mousetrap (a 3rd party library which is not shipped with AdapTable) and 2 using the native keydown event
- Each key press combination is tied to a different method in the Adaptable API to perform an action:
- 'alt+shift+s'- opens the Schedule popup (using Mousetrap)
- 'alt+shift+c'- opens the Calculated Column popup (using Mousetrap)
- 'metaKey+shiftKey+l'- opens the Layout popup (using keydown event)
- 'metaKey+shiftKey+s'- opens the Quick Search in Floating Mode (using keydown event)
### Expand to see the key bindings
```
// Define 2 Hotkeys using mousetrap - a 3rd party library (which is not shipped with AdapTable))
Mousetrap.bind('alt+shift+s', () =>
adaptableApi.scheduleApi.showSchedulePopup()
);
Mousetrap.bind('alt+shift+c', () =>
adaptableApi.calculatedColumnApi.showCalculatedColumnPopup()
);
// Define 2 hotkeys using NO dependency - just the native 'keydown' event
document.addEventListener('keydown', event => {
const {key, shiftKey, metaKey} = event;
// metaKey is 'command key' on Mac and 'windows key' on PC
if (key === 'l' && metaKey && shiftKey) {
event.preventDefault();
adaptableApi.layoutApi.showLayoutPopup();
}
if (key === 'q' && metaKey && shiftKey) {
event.preventDefault();
adaptableApi.quickSearchApi.showQuickSearchPopup();
}
```
- Try the different HotKey combinations or fork the project to add some of your own
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'HotKeys',
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
import Mousetrap from 'mousetrap';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
// Define 2 Hotkeys using mousetrap - a 3rd party library (which is not shipped with AdapTable))
Mousetrap.bind('alt+shift+s', () =>
adaptableApi.formatColumnApi.openFormatColumnSettingsPanel()
);
Mousetrap.bind('alt+shift+c', () =>
adaptableApi.calculatedColumnApi.openCalculatedColumnSettingsPanel()
);
// Define 2 hotkeys using NO dependency - just the native 'keydown' event
document.addEventListener('keydown', event => {
const {key, shiftKey, metaKey} = event;
// metaKey is 'command key' on Mac and 'windows key' on PC
if (key === 'l' && metaKey && shiftKey) {
event.preventDefault();
adaptableApi.layoutApi.openLayoutSettingsPanel();
}
if (key === 's' && metaKey && shiftKey) {
event.preventDefault();
adaptableApi.quickSearchApi.showFloatingQuickSearch();
}
});
};
```
---
# Developer Tutorials
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-overview
- Selection of tutorials designed to help Developers get the most out of AdapTable
### React
---
# Providing Adaptable Context
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context
- The `adaptableContext` property in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) allows individual context to be passed into AdapTable
- This can then be leveraged at runtime as required
The `adaptableContext` property allows developers to provide application-specific "context".
This object is very similar in intention to the [AG Grid Context object](https://www.ag-grid.com/javascript-data-grid/context/)
The property is set by developers in the root of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
It is subsequently passed by AdapTable into the [`BaseContext`](https://www.adaptabletools.com/docs/reference/basecontext.md) object.
- `BaseContext` is the base object supplied to most functions / callbacks in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md)
- It is also in the `xxxEventInfo` object included in all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md)
This allows developers to provide data or services which they can subsequently leverage elsewhere in AdapTable, e.g. in Custom [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) or [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-custom/index.md).
This [demo illustrates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md#extending-system-predicates) using Adaptable Context by providing a TimeZone Service leveraged by Custom Predicates
### `adaptableContext`
Custom Context for the Application
Set this property to provide custom context in your application.
```ts {3}
// Provide a Date Time Service to access in other callbacks
const adaptableOptions: AdaptableOptions = {
adaptableContext: {
dateTimeService: dateTimeService
}
}
```
## Demo
The demo below shows the typical pattern for using `adaptableContext`:
1. Build an application object — here a `currentUser` plus a tiny `userService` that answers permission questions
2. Put that object on `adaptableContext` once, alongside the rest of `AdaptableOptions`
3. Retrieve it from any AdapTable callback that needs it
**Example: Providing Adaptable Context**
Sharing a `currentUser` object and a `userService` helper via Adaptable Context
- The `userService.ts` file exports a `currentUser` object and a tiny `userService` with a `canPerform()` permission helper — both are plain TypeScript, with no framework dependencies
- `adaptableOptions.ts` then exposes them through `adaptableContext` and reads them back in **three** different places:
- **Config-time** — the `userName` option is set from `currentUser.name` and is displayed at the top-right of AdapTable
- **Runtime** — the `Edit` action button's `hidden` callback asks the `userService` whether the current user is allowed to edit
- **Runtime** — the `Delete` action button's `hidden` callback does the same for deleting
- The default user has the `Manager` role, so `Edit` is visible but `Delete` is hidden
- Edit `userService.ts` and change `currentUser.role` to `'Trader'` (both buttons disappear) or `'Admin'` (both buttons appear)
- Add another consumer — for example, a Custom Predicate handler — and access `currentUser` / `userService` exactly the same way via `adaptableContext`
```ts
/**
* A tiny "user session" module.
*
* It exports:
* - `currentUser` : plain data describing the active user
* - `userService` : a small helper that answers permission questions
*
* Both are pure TypeScript — no React, Vue, Angular or framework imports —
* so this same file is used unchanged across every framework Sandpack tab.
*/
export type UserRole = 'Trader' | 'Manager' | 'Admin';
export interface User {
name: string;
role: UserRole;
region: string;
}
/**
* The user driving this session. Try changing `role` to `'Trader'`,
* `'Manager'` or `'Admin'` to see how the action buttons in the grid
* change visibility.
*/
export const currentUser: User = {
name: 'Jane Smith',
role: 'Manager',
region: 'EMEA',
};
/**
* A trivial service. In a real application this might consult a
* permissions API or a feature-flag store; for the demo a single
* pure function is enough.
*/
export const userService = {
canPerform(user: User, action: 'edit' | 'delete'): boolean {
if (action === 'edit') {
return user.role !== 'Trader';
}
if (action === 'delete') {
return user.role === 'Admin';
}
return false;
},
};
```
```ts
import {
ActionColumnContext,
AdaptableButton,
AdaptableOptions,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
import {currentUser, userService} from './userService';
/**
* Three places consume the same `currentUser` + `userService` object:
*
* 1. `userName` — config-time string, read directly
* 2. `actionColumn['edit']` — runtime callback, reads from adaptableContext
* 3. `actionColumn['delete']` — runtime callback, reads from adaptableContext
*
* Nothing here is framework-specific — exactly the same file runs in the
* React, Vue, Angular and Vanilla Sandpack tabs.
*/
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Adaptable Context Demo',
// (1) Config-time usage — shown in the top-right of AdapTable
userName: currentUser.name,
// Single source of truth made available to every AdapTable callback
adaptableContext: {
currentUser,
userService,
},
actionColumnOptions: {
actionColumns: [
{
columnId: 'action',
friendlyName: 'Actions',
actionColumnButton: [
// (2) Runtime usage — Edit is hidden for Traders
{
command: 'edit',
tooltip: 'Edit row (Managers and Admins only)',
hidden: (
_button: AdaptableButton,
{adaptableContext}: ActionColumnContext
) =>
!adaptableContext.userService.canPerform(
adaptableContext.currentUser,
'edit'
),
},
// (3) Runtime usage — Delete is shown only to Admins
{
command: 'delete',
tooltip: 'Delete row (Admins only)',
hidden: (
_button: AdaptableButton,
{adaptableContext}: ActionColumnContext
) =>
!adaptableContext.userService.canPerform(
adaptableContext.currentUser,
'delete'
),
},
],
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'action',
'name',
'language',
'github_stars',
'license',
'created_at',
],
AutoSizeColumns: true,
},
],
},
},
};
```
---
# AdapTable Containers
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-containers
- Developers can configure custom Div elements that will be used by AdapTable
- These are configured using the ContainerOptions section of AdapTable Options
The Container Options section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains a series of properties allowing developers to specify various Div elements that can be used in Adaptable.
These include DIVs for [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) and [System Status Messages](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md), Popups and Transposed Grids.
- 2 containers are also available allowing developers to provide custom div names for AdapTable and AG Grid
- These are only required if using AdapTable vanilla - see [Setting AdapTable & AG Grid Containers](https://www.adaptabletools.com/docs/getting-started-setting-adaptable-aggrid-containers/index.md) for more details
AdapTable provides properties in Container Options.
All properties allow the container to be provided in one 4 ways:
- `string` — an element ID
- `AdaptableCssSelector` — a CSS selector
- `HTMLElement` — a direct reference to a DOM element
- a JavaScript function which returns any one of the above
### Providing the Container Value
Each container property returns an object of type [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md).
This can return one of 3 values:
- string: an element ID - which isresolved via `document.getElementById`
- `AdaptableCssSelector`: a CSS selector - resolved via `document.querySelector`
- `HTMLElement`: a direct reference to a DOM element
If the property uses a function it receives an object of type [`ContainerContext`](https://www.adaptabletools.com/docs/reference/containercontext.md) and returns an [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md).
The `ContainerContext` is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [adaptableApi](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable Api object |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
| [adaptableId](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptableid) | `string` | Id of current AdapTable instance |
| [adaptableStateKey](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptablestatekey) | `string` | Current Adaptable State Key |
| [clientTimestamp](https://www.adaptabletools.com/docs/reference/basecontext.md#clienttimestamp) | `Date` | Time on user's computer |
| [userName](https://www.adaptabletools.com/docs/reference/basecontext.md#username) | `string` | Name of Current User |
## CSS Selector
The [`AdaptableCSSSelector`](https://www.adaptabletools.com/docs/reference/adaptablecssselector.md) object is used to locate a DOM element.
It contains a single `selector` property which is designed to target elements by CSS selectors (e.g. class, attribute, etc.) rather than elementID:
| Property | Type | Description |
| --- | --- | --- |
| [selector](https://www.adaptabletools.com/docs/reference/adaptablecssselector.md#selector) | `string` | CSS Selector that locates DOM element |
The property can be used in multiple different ways, e.g.
```ts
selector: '#my-container'
selector: '.dashboard-panel'
selector: '[data-container="alerts"]' }
```
## Alert Container
[Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) in AdapTable can be given a number of [Alert behaviours](https://www.adaptabletools.com/docs/handbook-alerting-behaviours/index.md).
One behaviour is to display details of the Alert in a Div elmement configured in the `alertContainer` property.
### `alertContainer`
Div where Alerts can appear
[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)
Name of the Div where [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md) can be displayed.
The property can be either the Id (string) of the Div or the HTMLElement itself.
And it can either be returned directly:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
alertContainer: 'myAlertContainer',
},
};
```
or via a function:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
alertContainer: (context: ContainerContext) => {
return document.getElementById('myAlertContainer');
},
},
};
```
## Modal Container
AdapTable, by default, will display the Settings Panel and popups in the centre of the screen above the Grid.
If this is not required behaviour, the `modalContainer` property can specify an alternative location.
### `modalContainer`
Div which contains AdapTable popups
[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)
Name of the Div which contains the Settings Panel - and any other AdapTable popups.
The property can be either the Id (string) of the Div or the HTMLElement itself.
And it can either be returned directly:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
modalContainer: 'myModalContainer',
},
};
```
or via a function:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
modalContainer: (context: ContainerContext) => {
return document.getElementById('myModalContainer');
},
},
};
```
## System Status Container
AdapTable offers [System Status Messages](https://www.adaptabletools.com/docs/handbook-system-status-message/index.md) which will display important messages to run time users.
These can be displayed in various locations in the AdapTable UI, including in a custom div specified by using the `systemStatusContainer` property.
### `systemStatusContainer`
Div where System Status messages can appear
[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)
Name of the Div where [System Status](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) messages can be displayed.
The property can be either the Id (string) of the Div or the HTMLElement itself.
And it can either be returned directly:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
systemStatusContainer: 'mySystemStatusContainer',
},
};
```
or via a function:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
systemStatusContainer: (context: ContainerContext) => {
return document.getElementById('mySystemStatusContainer');
},
},
};
```
## Transposed View Container
AdapTable supports [displaying a transposed view](https://www.adaptabletools.com/docs/handbook-transposing/index.md) of AG Grid data.
By default AdapTable displays the transposed content (grid and column selector) in a popup above AG Grid.
However developers can choose to display the Transposed View in any container of their choice by using the `transposedViewContainer` property.
- Transposed View content is rendered directly into this container **without** the default popup window chrome
- This means that, by default, no header or close button are displayed, and the window is not draggable
The container is responsible for its own lifecycle; removing it from the DOM will cleanly unmount the Transposed View
### `transposedViewContainer`
Div where Transposed Views are displayed
[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)
The property can be either the Id (string) of the Div or the HTMLElement itself.
And it can either be returned directly:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
transposedViewContainer: 'myTransposedViewContainer',
},
};
```
or via a function:
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
transposedViewContainer: (context: ContainerContext) => {
return document.getElementById('myTransposedViewContainer');
},
},
};
```
## Container Options Reference
This is the full list of properties available in Container Options:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [adaptableContainer](https://www.adaptabletools.com/docs/reference/containeroptions.md#adaptablecontainer) | [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)` \| ((context: `[`InitContainerContext`](https://www.adaptabletools.com/docs/reference/initcontainercontext.md)`) => `[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)`)` | Div containing AdapTable; element Id, CSS Selector, HTMLElement, or function returning one of these | "adaptable" |
| [agGridContainer](https://www.adaptabletools.com/docs/reference/containeroptions.md#aggridcontainer) | [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)` \| ((context: `[`InitContainerContext`](https://www.adaptabletools.com/docs/reference/initcontainercontext.md)`) => `[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)`)` | Div containing AG Grid instance; element Id, CSS Selector, HTMLElement, or function returning one of these. | "grid" |
| [alertContainer](https://www.adaptabletools.com/docs/reference/containeroptions.md#alertcontainer) | [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)` \| ((context: `[`ContainerContext`](https://www.adaptabletools.com/docs/reference/containercontext.md)`) => `[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)`)` | Div to display Alerts; elementId, CSS Selector, HTMLElement, or function returning one of these | undefined |
| [modalContainer](https://www.adaptabletools.com/docs/reference/containeroptions.md#modalcontainer) | [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)` \| ((context: `[`ContainerContext`](https://www.adaptabletools.com/docs/reference/containercontext.md)`) => `[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)`)` | Name of div where popups appear;element Id, CSS Selector, HTMLElement, or function returning one of these | undefined (centre of screen) |
| [systemStatusContainer](https://www.adaptabletools.com/docs/reference/containeroptions.md#systemstatuscontainer) | [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)` \| ((context: `[`ContainerContext`](https://www.adaptabletools.com/docs/reference/containercontext.md)`) => `[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)`)` | Div to show System Status Messages; elementId, CSS Selector, HTMLElement, or function returning one of these | undefined |
| [transposedViewContainer](https://www.adaptabletools.com/docs/reference/containeroptions.md#transposedviewcontainer) | [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)` \| ((context: `[`ContainerContext`](https://www.adaptabletools.com/docs/reference/containercontext.md)`) => `[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)`)` | Div to render a Transposed View; elementId, CSS Selector, HTMLElement, or function returning one of these | undefined (rendered in a draggable popup window) |
---
# Setting Cell Editability
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-setting-cell-editability
- This tutorial describes the 2 different ways that Cell Editability can be set in AG Grid and AdapTable
- It also explains AdapTable takes preference over AG Grid when evaluating editability
## Editability Use Cases
There are many use cases when AdapTable will asses whether a given Cell in AG Grid is editable, e.g.:
- When the user starts editing a cell directly
- Rendering the [ReadOnly or Editable Cell Styles](https://www.adaptabletools.com/docs/ui-tutorial-editable-styles/index.md)
- Providing the [Smart Edit](https://www.adaptabletools.com/docs/handbook-editing-smart-edit/index.md) or [Bulk Update](https://www.adaptabletools.com/docs/handbook-editing-bulk-update/index.md) menu items for the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md)
- When opening a [Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md) field
## Setting Readonly Columns
There are 2 main ways in which cells (or columns) can be marked as editable or readonly:
- The `colDef.editable` in AG Grid GridOptions - a boolean (or boolean callback)
- Like all ColDef properties, this defaults to _false_ so, if not provided, the Column is readonly
- And, like all ColDef properties, it can be set directly in each Column or by using `defaultColDef`
- The [isCellEditable](https://www.adaptabletools.com/docs/handbook-validating-pre-edit/index.md#setting-editable-cells) function in [Edit Options](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md)
## AdapTable Rules of Evaluation
AdapTable takes account of both of these of ways to set cell editability.
**First it will evaluate** the [isCellEditable](https://www.adaptabletools.com/docs/handbook-validating-pre-edit/index.md#setting-editable-cells) property in Edit Options, if provided, and return the result.
If `isCellEditable` is not provided, AdapTable will evaluate `colDef.editable` in GridOptions - either as a boolean property or callback.
- You can evaluate just a subset of columns in `isCellEditable` by returning `context.defaultColDefEditableValue`
- This tells AdapTable to return the default editability value for the cell (i.e. what is in `colDef.editable`)
---
# Setting Up Team Sharing
Canonical page: https://www.adaptabletools.com/docs/dev-guide-tutorial-team-sharing
- This brief guide looks at the 4 mandatory steps involved in setting up [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md) in Adaptable
---
# Using the Demos
Canonical page: https://www.adaptabletools.com/docs/documentation-demo-list
- This Documentation includes many small Demos
- Most Demos contain the same small data set that show the a list of popular JavaScript Frameworks
- The Demos can be set to run in 3 flavours:
- using AdapTable Vanilla
- using AdapTable Rect
- using AdapTable Angular
- using AdapTable Vue
- Each Demo highlights a particular Module or piece of functionality with options to:
- Switch between code view and grid view
- Open the Demo in Full Screen
- Fork the Demo in Sandbox to make changes and run independently
- Reset to remove any changes made to the Demo
- Most Demos also include:
- Description and explanation of what the Demo does
- Key code snippets of interest
- Suggestions to try things out
The AdapTable documentation is liberally sprinkled with hundreds of Demos.
Every Demo illustrates a different piece of functionality or use case.
Each Demo is a full featured AdapTable (and AG Grid) instance that uses [Sandpack](https://codesandbox.io/blog/sandpack-announcement).
## Contents of the Demos
The Demos are designed to be as instructive, educational and helpful as possible.
Accordingly each Demo contains these features:
- ability between to toggle between showing the **Code** and seeing the **AdapTable** instance
- option to view the Demo in **Full Screen**
In full screen the Code and the AdapTable instance can be viewed side be side
- **Reset** button to undo any changes made and revert to the original version of the Demo
- **Fork** button to run the Demo in *Codesandbox*
- Running a Demo in CodeSandbox is a good way to see how the particular Framework builds the full Demo
- It also allows you easily to change the Initial Adaptable State or Adaptable Options and view the results
- **Description** summarising what the Demo is designed to illustrate
- expandable **Show More** button which displays the most important snippet of code used
- **Try It Out** suggestion giving tips for something the user might want to try
### Code View
Code View provides the most important code files that were used to create the Demo.
It typically includes:
- `adaptableOptions.ts` - the [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) used in the Demo (including any [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md))
- `gridOptions.ts` - the [AG Grid Grid Options](https://www.ag-grid.com/javascript-data-grid/grid-options/) file used
- `columnDefs.ts` - the [AG Grid Column Definitions](https://www.ag-grid.com/javascript-data-grid/column-definitions/) provided to Grid Options
- `agGridModules.ts` - the [AG Grid Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) used in the Demo (typically the full set that AdapTable requires)
and when required (i.e. when the Event has been subscribed):
- `onAdaptableReady.ts` - the code provided in the [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) for the Demo
- In the real world you are unlikely to create a file just to listen to the Adaptable Ready Event
- It's provided here to minimise the code provided, and only display what is relevant to the particular Demo
## Setting the Framework
AdapTable comes in 4 versions, and each of these can be used to power the Demos:
- Vanilla (TypeScript)
- [AdapTable React](https://www.adaptabletools.com/docs/index.md)
- [AdapTable Angular](https://www.adaptabletools.com/docs/index.md)
- [AdapTable Vue](https://www.adaptabletools.com/docs/index.md)
We show the Framework being used in the top left corner of each Demo Sandpack
By default, all Demos will be written using AdapTable TypeScript.
But this can be changed by clicking the required Framework button in the top right of each page.
- In practice there is not much difference between the Frameworks in the Demos when they are displayed inside Help
- However forking a Demo to open it in Codesandbox, shows all the code provided in a fully Framework-specific way
- Some Demos can **only** be displayed in a particular Framework and the global Framework setting is ignored
- For instance the Demos which create React or Angular Components or shows No Code (which is React only)
### The Data Set
The overwhelming majority of the Demos contain the same Data Set.
It contains 25 rows, each showing the Github record of a different JavaScript framework.
A small Data Set allows each example to focus on a separate piece of functionality, rather than overall performance
- There are a few Demos in the Documentation which do contain much bigger Data Sets
- One good example is the [Adaptable Performance Demo](https://www.adaptabletools.com/docs/dev-guide-support-adaptable-performance/index.md) which contains 100,000 rows
- Another are the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) and [Viewport Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-viewport/index.md) Demos which both use infinite data
## Demo List
This is the full list of Demos available in the Documentation.
Click to open the Demo of your choice.
---
# Using the AdapTable for AG Grid Documentation
Canonical page: https://www.adaptabletools.com/docs/documentation-overview
- Guide to this documentation - describes the contents of each section
- Explains what regular pages mean (e.g. Using, Configuring, Technical Reference)
- Information on the demos and videos included in the documentation
This documentation aims to provide developers using AdapTable with everything they need to access the tool and shape it to meet their particular requirements.
- These Help Pages support the latest version of AdapTable ([23](https://www.adaptabletools.com/support/version-230-release-note))
- There is full documentation available for [older AdapTable versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md)
The AdapTable documentation contains hundreds of help pages and demos designed to help new users get up and running quickly with AdapTable, and for existing users to find the information they need.
- This documentation is being continually expanded, and we aim to make it as comprehensive as possible
- Please contact the [AdapTable Team](https://www.adaptabletools.com/buy/buying-adaptable-contact-us) with any questions, suggestions and feedback
## Framework Picker
The documentation is designed to run seamlessly according to the Selected Framework.
You can select a Framework by using the Framework Picker in the Header, which allows you to see integration, installation and custom component information for your selected framework.
It also ensures that the demos run automatically using the same Framework
There are 4 Framework variants:
- [AdapTable Vanilla (TypeScript)](https://www.adaptabletools.com/docs/index.md)
- [AdapTable React](https://www.adaptabletools.com/docs/index.md)
- [AdapTable Angular](https://www.adaptabletools.com/docs/index.md)
- [AdapTable Vue](https://www.adaptabletools.com/docs/index.md)
## Sections
The documentation is divided into a number of sections:
- Getting Started - everything you need to know to get up and running with AdapTable
- Layouts - creating Table and Pivot Layouts in order to manage Columns, Grouping, Aggregations etc
- UI Components - overview of AdapTable UI surfaces (Dashboard, Settings Panel, Tool Panel, menus) plus theming and UI guides
- Core Features - most popular AdapTable features e.g. Alerts, Calculated Columns, Annotations etc.
- Searching & Filtering - how to use Quick Search, Column & Grid Filters and Data Set features
- Cell Rendering - using Format Columns, Conditional Styles, Styled Columns & Flashing Cells
- Editing - AdapTable's many editing modules, Validation, Data Change History, Cell Editors & Row Forms
- Grid Data - Exporting & Importing, Sorting, Selecting & Summarising data in AG Grid
- Advanced Features - Team Sharing, Scheduling and FDC3 Support
- Developer Guide - Everything developers needs e.g. State Management, key types, Tutorials etc.
- Technical Reference - Overview of Adaptable Options, Initial Adaptable State, AdapTable API, Events, Plugins
- AdapTableQL - Guide to Predicates and Expressions provided by AdapTable's native Query Language
- Partner Integrations - Instructions on how to use AdapTable with ipushpull, OpenFin, interop.io
## Regular Pages
We try to be consistent within each section in terms of how pages are named.
In particular 2 pages appear in many sections:
### Configuring
A "Configuring" page will explain how developers are able to leverage the feature.
It will typically one or both types of design-time configuration as required:
- Any [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) that needs to be defined
- Any [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) that can be configured
### Technical Reference
Anything technical for that module is included in a "Technical Reference" page which can include any or all of:
- [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md)
- [Adaptable Options Properties](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md)
- [Adaptable API Class](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md)
- [Adaptable Event](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md)
- Some sections also have a "Using" page which explains what **run-time** users are able to do
- It will typically include guides to using relevant wizards and explain how and where the feature can be accessed.
### FAQs
Many pages include a section contain relevant Frequently Asked Questions.
### AdapTable Resources
Some pages will include an AdapTable Resources section that links to relevant material.
## Older Versions
AdapTable maintains versions of the documentation from AdapTable 12 onwards.
See the [older versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md) of the AdapTable documentation
## Demos
The documentation includes a huge amount of [demo examples](https://www.adaptabletools.com/docs/documentation-demo-list/index.md).
Each demo is designed to show a particular feature of module with all the code provided.
- The majority of the demos show AdapTable using the `dark` Theme as that is generally the most popular
- But this can be changed in each demo through the Settings Panel or Tool Panel
Each demo will run automatically using the Framework selected in the framework picker at the top of the page.
The AdapTable documentation is liberally sprinkled with hundreds of Demos.
Every Demo illustrates a different piece of functionality or use case.
Each Demo is a full featured AdapTable (and AG Grid) instance that uses [Sandpack](https://codesandbox.io/blog/sandpack-announcement).
### Contents of the Demos
The Demos are designed to be as instructive, educational and helpful as possible.
Accordingly each Demo contains these features:
- ability between to toggle between showing the **Code** and seeing the **AdapTable** instance
- option to view the Demo in **Full Screen**
In full screen the Code and the AdapTable instance can be viewed side be side
- **Reset** button to undo any changes made and revert to the original version of the Demo
- **Fork** button to run the Demo in _Codesandbox_
- Running a Demo in CodeSandbox is a good way to see how the particular Framework builds the full Demo
- It also allows you easily to change the Initial Adaptable State or Adaptable Options and view the results
- **Description** summarising what the Demo is designed to illustrate
- expandable **Show More** button which displays the most important snippet of code used
- **Try It Out** suggestion giving tips for something the user might want to try
### Code View
Code View provides the most important code files that were used to create the Demo.
It typically includes:
- `adaptableOptions.ts` - the [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) used in the Demo (including any [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md))
- `gridOptions.ts` - the [AG Grid Grid Options](https://www.ag-grid.com/javascript-data-grid/grid-options/) file used
- `columnDefs.ts` - the [AG Grid Column Definitions](https://www.ag-grid.com/javascript-data-grid/column-definitions/) provided to Grid Options
- `agGridModules.ts` - the [AG Grid Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) used in the Demo (typically the full set that AdapTable requires)
and when required (i.e. when the Event has been subscribed):
- `onAdaptableReady.ts` - the code provided in the [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) for the Demo
### The Data Set
The overwhelming majority of the Demos contain the same Data Set.
It contains 25 rows, each showing the Github record of a different JavaScript framework.
A small Data Set allows each example to focus on a separate piece of functionality, rather than overall performance
See [Showcase Demos](https://www.adaptabletools.com/docs/showcase-demos-overview/index.md) for integrated demos that show multiple features working together
### Appendix: Demo List
This is the full list of Demos available in the Documentation.
Click to open the Demo of your choice.
---
# Older AdapTable Versions
Canonical page: https://www.adaptabletools.com/docs/documentation-previous-versions
- All versions of the AdapTable Documentation from Version 12 onwards are available
AdapTable provides developers with documentation for older versions of the software from 12 onwards.
These versions will remain available on npm indefinitely.
- We only make enhancements, fix bugs, and add new features, to the [Current Version](https://www.adaptabletools.com/support/release-schedule) of AdapTable
- However, we do support all previous versions in the form of responding to queries and answering "how to" requests
## AdapTable Version History
### Version 22
- [Main Documentation](https://v22.adaptabletools.com/docs/)
- **TypeScript**
- [Installation](https://v22.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v22.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v22.adaptabletools.com/docs/react-installation)
- [Integration](https://v22.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v22.adaptabletools.com/docs/angular-installation)
- [Integration](https://v22.adaptabletools.com/docs/angular-integration)
- **Vue**
- [Installation](https://v22.adaptabletools.com/docs/vue-installation)
- [Integration](https://v22.adaptabletools.com/docs/vue-integration)
### Version 21
- [Main Documentation](https://v21.adaptabletools.com/docs/)
- **TypeScript**
- [Installation](https://v21.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v21.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v21.adaptabletools.com/docs/react-installation)
- [Integration](https://v21.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v21.adaptabletools.com/docs/angular-installation)
- [Integration](https://v21.adaptabletools.com/docs/angular-integration)
- **Vue**
- [Installation](https://v21.adaptabletools.com/docs/vue-installation)
- [Integration](https://v21.adaptabletools.com/docs/vue-integration)
### Version 20
- [Main Documentation](https://v20.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v20.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v20.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v20.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v20.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v20.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v20.docs.adaptabletools.com/docs/angular-integration)
- **Vue**
- [Installation](https://v20.docs.adaptabletools.com/docs/vue-installation)
- [Integration](https://v20.docs.adaptabletools.com/docs/vue-integration)
### Version 19
- [Main Documentation](https://v19.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v19.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v19.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v19.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v19.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v19.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v19.docs.adaptabletools.com/docs/angular-integration)
- **Vue**
- [Installation](https://v19.docs.adaptabletools.com/docs/vue-installation)
- [Integration](https://v19.docs.adaptabletools.com/docs/vue-integration)
### Version 18
- [Main Documentation](https://v18.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v18.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v18.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v18.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v18.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v18.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v18.docs.adaptabletools.com/docs/angular-integration)
### Version 17
- [Main Documentation](https://v17.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v17.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v17.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v17.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v17.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v17.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v17.docs.adaptabletools.com/docs/angular-integration)
### Version 16
- [Main Documentation](https://v16.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v16.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v16.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v16.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v16.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v16.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v16.docs.adaptabletools.com/docs/angular-integration)
### Version 15
- [Main Documentation](https://v15.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v15.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v15.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v15.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v15.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v15.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v15.docs.adaptabletools.com/docs/angular-integration)
### Version 14
- [Main Documentation](https://v14.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v14.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v14.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v14.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v14.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v14.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v14.docs.adaptabletools.com/docs/angular-integration)
### Version 13
- [Main Documentation](https://v13.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v13.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v13.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v13.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v13.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v13.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v13.docs.adaptabletools.com/docs/angular-integration)
### Version 12
- [Main Documentation](https://v12.docs.adaptabletools.com/)
- **TypeScript**
- [Installation](https://v12.docs.adaptabletools.com/docs/getting-started-installation)
- [Integration](https://v12.docs.adaptabletools.com/docs/getting-started-integration)
- **React**
- [Installation](https://v12.docs.adaptabletools.com/docs/react-installation)
- [Integration](https://v12.docs.adaptabletools.com/docs/react-integration)
- **Angular**
- [Installation](https://v12.docs.adaptabletools.com/docs/angular-installation)
- [Integration](https://v12.docs.adaptabletools.com/docs/angular-integration)
---
# Watching the Videos
Canonical page: https://www.adaptabletools.com/docs/documentation-video-list
- The AdapTable documentation includes many video guides
- They typically show a Module or function or highlight newly added features
- This page lists all the Videos which are available, and the AdapTable version it uses
- Click to navigate to the video of your choice
---
# Setting AdapTable ID
Canonical page: https://www.adaptabletools.com/docs/getting-started-adaptable-id
- The AdapTableId property in Adaptable Options is used to uniquely idenitfy the current AdapTable instance
The `adaptableId` property sets how each instance of AdapTable is identified and named.
The property is set in the root of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
### `adaptableId`
Identifier for the current Adaptable instance
Sets the name of the current AdapTable instance
```ts {2}
const adaptableOptions: AdaptableOptions = {
adaptableId: "Trading Grid"
}
```
The `adaptableId` property is used in a number of places in AdapTable including:
- the key in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) if using local storage (and no `adaptableStateKey` property has been provided)
- the default value for the `DashboardTitle` property in [Dashboard Initial State](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md) (i.e. what is displayed in the [Dashboard Header](https://www.adaptabletools.com/docs/ui-dashboard/index.md))
- in [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing/index.md) to identify the current instance
Ensure to provide your own value for `adaptableId` so that you can easily identify different AdapTable instances
It is particularly useful when you have multiple AdapTable Grids displaying simultaneously.
- Although AdapTable provides a default if this property is not supplied, we strongly recommend that you do so
- This will avoid future conflicts between multiple AdapTable instances
## Base Context
The value of the `adaptableId` property is suppled in the very commonly used [`Base Context`](https://www.adaptabletools.com/docs/reference/basecontext.md); this is the base of the `xxxContext` properties supplied to most functions in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md), and also the base of the `xxxEventInfo` object included in all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md)
---
# Adaptable Ready Event
Canonical page: https://www.adaptabletools.com/docs/getting-started-adaptable-ready
- Event published by AdapTable as soon as it has initialised
- Provides access to the Adaptable API object and AG Grid API object
The Adaptable Ready Event fires when AdapTable has finished initialising and is ready to be accessed.
## AdaptableReadyInfo
It comprises an [`AdaptableReadyInfo`](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md) object containing an `agGridApi` property (representing AG Grid's Api):
| Property | Type | Description |
| --- | --- | --- |
| [agGridApi](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md#aggridapi) | [`GridApi`](https://www.adaptabletools.com/docs/reference/gridapi.md)`` | Underlying AG Grid API |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
## BaseContext
The `AdapTableReadyInfo` object inherits from the [`BaseContext`](https://www.adaptabletools.com/docs/reference/basecontext.md) object.
This contains the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) object which provides run-time, programmatic access to all AdapTable's objects and functionality, as well as the [Adaptable Id](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md), [User Name](https://www.adaptabletools.com/docs/getting-started-user-name/index.md) and other properties:
| Property | Type | Description |
| --- | --- | --- |
| [adaptableApi](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptableapi) | [`AdaptableApi`](https://www.adaptabletools.com/docs/reference/adaptableapi.md) | Adaptable Api object |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
| [adaptableId](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptableid) | `string` | Id of current AdapTable instance |
| [adaptableStateKey](https://www.adaptabletools.com/docs/reference/basecontext.md#adaptablestatekey) | `string` | Current Adaptable State Key |
| [clientTimestamp](https://www.adaptabletools.com/docs/reference/basecontext.md#clienttimestamp) | `Date` | Time on user's computer |
| [userName](https://www.adaptabletools.com/docs/reference/basecontext.md#username) | `string` | Name of Current User |
## Event Subscription
Subscribing to the Event is done the same way as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md):
```ts
api.eventApi.on('AdaptableReady', (eventInfo: AdaptableReadyInfo) => {
// do something with the info
});
```
## Framework Components
The `AdaptableReady` event is particularly useful when using one of the Framework versions (ie. AdapTable React, AdapTable Angular or AdapTable Vue).
This is because it provides access to 2 very important objects:
- [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) - for programmatic access to AdapTable
- [AG Grid's `Grid API`](https://www.ag-grid.com/javascript-data-grid/grid-api/) - for programmatic access to AG Grid
---
# AdapTable State Key
Canonical page: https://www.adaptabletools.com/docs/getting-started-adaptable-state-key
- The AdapTable State Key is used primarily to identify the current AdapTable instance when using local storage
- But it can also be used to distinguish between multiple different remote state collections
The `adaptableStateKey` property is primarily used in conjunction with [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
It is used to identify the current AdapTable instance when using [Local Storage](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#local-storage)
If this is not provided, AdapTable will use the value provided in the [adaptableId](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md) property
The property is set in the root of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
You can also use `adaptableStateKey` to distinguish multiple AdapTable States when using [Remote Storage](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#remote-storage)
### `adaptableStateKey`
Identifier used as localStorage persistence key for AdaptableState
Set the name of the State to something identifiable
```ts {2}
const adaptableOptions: AdaptableOptions = {
adaptableStateKey: 'myGridInstance',
}
```
---
# AG Grid Modules
Canonical page: https://www.adaptabletools.com/docs/getting-started-aggrid-modules
- AG Grid provides functionality via Modules
- These are available either as a Bundle, or individually selected
- Some AG Grid Modules are mandatory in AdapTable, while others are required for certain features to work
AG Grid provides its functionality through a series of [AG Grid Modules](https://ag-grid.com/javascript-data-grid/modules/).
Since AG Grid 33 this has been available in 2 forms:
- as a bundle (everything in AG Grid Enterprise is available)
- as specific modules (in order to reduce download size)
AG Grid modules must be registered regardless whether you use [ESM (standard) or CommonJS](https://www.adaptabletools.com/docs/getting-started-installation/index.md#esm-and-cjs-formats) formats
## AllEnterpriseModule Bundle
AG Grid provide an `AllEnterpriseModule` bundle which contains **all** of the modules available in Community and Enterprise versions.
This is the easiest option as it guarantees that everything required by AG Grid (and AdapTable) is present.
Using this bundle essentially replicates the behaviour of AG Grid packages prior to version 33
## Selecting Modules
Alternatively, you can register only the modules you want to use in your application.
This allows you to reduce the bundle size of your application (but requires more considered thought).
AG Grid provides a useful [Module Selector](https://www.ag-grid.com/javascript-data-grid/modules/#selecting-modules) to see what is required for your use case from an AG Grid perspective
AdapTable leverages [AG Grid Modules](https://ag-grid.com/javascript-data-grid/modules/) for much of its functionality - both core and feature-specific.
As a result, it is useful to divide the AG Grid Modules into 3 groups:
| Group | Description |
| --------------- | ------------------------------------------------------------------------------------ |
| **Mandatory** | Without these AG Grid Modules, AdapTable simply won't work, so they must be supplied |
| **Per-Feature** | AG Grid Modules which are needed on a per-feature basis |
| **Avoid** | Using these AG Grid Modules can cause issues, so should be avoided |
### Mandatory Modules
There are some Modules which **must be registered** for AdapTable to work.
Without these modules, AdapTable will either not start or will display significant errors at start-up
You must provide the relevant Module, and associated API, for the AG Grid RowModel you are using.
#### Client-Side Row Model
For the (default\_ Client Side Row Model you need to provide:
- `ClientSideRowModelModule`
- `ClientSideRowModelApiModule`
#### Server-Side Row Model
If you are using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md), you need to provide
- `ServerSideRowModelModule`
- `ServerSideRowModelApiModule`
Additionally there are a number of AG Grid API Modules that AdapTable uses to tie everything together:
#### All Row Models
There are some Modules that need to be provided irrespective of the Row Model being used.
All of these are **mandatory** and must be provided for a seamless and error-free user experience
- `CellStyleModule`
- `ColumnMenuModule`
- `ContextMenuModule`
- `CustomFilterModule`
- `ExternalFilterModule`
- `GridStateModule`
- `GroupFilterModule`
- `RowGroupingModule`
- `RowStyleModule`
- `CellApiModule`
- `ColumnApiModule`
- `EventApiModule`
- `RenderApiModule`
- `RowApiModule`
- `ScrollApiModule`
### Per-Feature Modules
Additional AG Grid Modules must be registered to enable using their specific features in AdapTable.
Without these modules, certain functionalities in AdapTable will be limited or unavailable
Here is the full list of AG Grid Modules which AdapTable requires (on a per-feature basis):
| AG Grid Module | Where Used |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CellSelectionModule` | [Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising-cells/index.md), [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) and [Selecting Data](https://www.adaptabletools.com/docs/handbook-selecting/index.md) |
| `ColumnAutoSizeModule` | [Layout Auto-Sizing](https://www.adaptabletools.com/docs/handbook-layouts-table-column-sizing/index.md#auto-sizing-in-layout) |
| `CsvExportModule` | [CSV Export Report Format](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md#csv) |
| `ExcelExportModule` | [Excel and VisualExcel Report Formats](https://www.adaptabletools.com/docs/handbook-exporting-reports-format-type/index.md#excel) |
| `FindModule` | [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md) |
| `IntegratedChartsModule` | If using AG Grid's [Charts](https://www.adaptabletools.com/docs/handbook-charts/index.md) functionality |
| `MasterDetailModule` | By the [Master Detail](https://www.adaptabletools.com/docs/handbook-master-detail/index.md) Plugin |
| `PinnedRowModule` | [Row Summaries](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md) |
| `PivotModule` | [Pivoting](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) |
| `QuickFilterModule` | Running [Quick Search as Filter](https://www.adaptabletools.com/docs/handbook-quick-search-as-filter/index.md) |
| `RichSelectModule` | If using [Select Editors](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) |
| `RowSelectionModule` | Needed for [Selecting](https://www.adaptabletools.com/docs/handbook-selecting/index.md) via Grid Api |
| `SideBarModule` | [Adaptable ToolPanel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) |
| `SparklinesModule` | [Sparkline Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md) |
| `StatusBarModule` | [Adaptable Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) |
| `TextEditorModule` | Used for [editing](https://www.adaptabletools.com/docs/handbook-editing/index.md) (all columns) |
| `TooltipModule` | [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) & many [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) |
| `TreeDataModule` | If using the [Tree Grid](https://www.adaptabletools.com/docs/handbook-tree-data-grid/index.md) |
### To Be Avoided Modules
AG Grid provides a `SetFilterModule` - which it uses in its filtering.
However AdapTable provides its filtering independently.
As a result, importing this module causes issues as AG Grid sets it as the default filter type, overriding AdapTable's filter implementation.
For this reason, we strongly recommend **not importing or registering** the `SetFilterModule`
A workaround if you absolutely require this Module is setting `gridOptions.suppressSetFilterByDefault` prop to _true_
## Appendix: All AG Grid Modules
This is the full list of AG Grid Modules (listed in the same order as [AG Grid does](https://www.ag-grid.com/javascript-data-grid/modules/#selecting-modules))
We indicate whether it is required, or used by AdapTable, and if so, where:
| AG Grid Module | Purpose | AdapTable Behaviour |
| ----------------------------- | ------------------------- | ---------------------------------------------- |
| `ColumnAutoSizeModule` | Column Auto-Sizing | Auto Sizing Layouts |
| `ColumnHoverModule` | Column Hovering | n/a |
| `PinnedRowModule` | Pinning Rows | Row Summaries |
| `RowAutoHeightModule` | Auto Row Height | n/a |
| `RowStyleModule` | Styling Rows | **Mandatory** |
| `PaginationModule` | Row Pagination | n/a |
| `RowDragModule` | Row Dragging | n/a |
| `RowNumbersModule` | Numbering Rows | n/a |
| `CellSpanModule` | Spanninng Cells | n/a |
| `CellStyleModule` | Stylingg Cells | **Mandatory** |
| `HighlightChangesModule` | Highlighting Changes | n/a |
| `TooltipModule` | Tooltips | In Calculated Columns & Styled Columns |
| `FindModule` | Find | Quick Search |
| `TextFilterModule` | Text Filter | Ignored by AdapTable |
| `NumberFilterModule` | Number Filter | Ignored by AdapTable |
| `DateFilterModule` | Date Filter | Ignored by AdapTable |
| `SetFilterModule` | Set Filter | Can break AdapTable - **do not provide** |
| `MultiFilterModule` | Multi Filter | Ignored by AdapTable |
| `CustomFilterModule` | Custom Filter | **Mandatory** |
| `AdvancedFilterModule` | Advanced Filter | Ignored by AdapTable |
| `ExternalFilterModule` | External Filter | **Mandatory** |
| `QuickFilterModule` | Quick Filter | Quick Search (Filter Results) |
| `RowSelectionModule` | Row Selection | Needed for Row Select Api methods |
| `CellSelectionModule` | Cell Selection | Needed for Cell Select Api methods |
| `TextEditorModule` | Text Editor | Used for editing (all columns) |
| `LargeTextEditorModule` | Large Text Editor | n/a |
| `SelectEditorModule` | Select Editor | n/a |
| `RichSelectEditorModule` | Rich Select Editor | Used for Adaptable Select Cell Edits |
| `NumberEditorModule` | Number Editor | n/a |
| `DateEditorModule` | Date Editor | n/a |
| `CheckboxEditorModule` | Checkbox Editor | n/a |
| `CheckboxEditorModule` | Custom Cell Editor | n/a |
| `CheckboxEditorModule` | Undo / Redo Edits | n/a |
| `BatchEditorModule` | Batch Edits | n/a |
| `LocaleModule` | Localisation | n/a |
| `RowGroupingModule` | Row Grouping | **Mandatory** |
| `RowGroupingPanelModule` | Row Grouping Panel | n/a |
| `GroupFilterModule` | Row Grouping | **Mandatory** |
| `PivotModule` | Pivoting | Pivot Layouts |
| `TreeDataModule` | Tree Data | Tree Grids |
| `MasterDetailModule` | Master Detail | Master Detail plugin |
| `SideBarModule` | Side Bar | AdapTable Tool Panel |
| `ColumnsToolPanelModule` | Columns Tool Panel | n/a |
| `FiltersToolPanelModule` | Filters Tool Panel | n/a |
| `New FiltersToolPanelModule` | New Filters Tool Panel | n/a |
| `ColumnMenuModule` | Column Menu | **Mandatory** |
| `ContextMenuModule` | Context Menu | **Mandatory** |
| `StatusBarModule` | Status Bar | AdapTable Status Panels |
| `CsvExportModule` | CSV Export | CSV Export Report Format |
| `ExcelExportModule` | Excel Export | Excel Export Report Format |
| `ClipboardModule` | Clipboard | n/a |
| `DragAndDropModule` | Drag & Drop | n/a |
| `ValueCacheModule` | Value Cache | n/a |
| `AlignedGridsModule` | Aligned Grids | n/a |
| `GridStateModule` | Grid State | **Mandatory** |
| `ColumnApiModule` | Column API | **Mandatory** |
| `RowApiModule` | Row API | **Mandatory** |
| `CellApiModule` | Cell API | **Mandatory** |
| `ScrollApiModule` | Scrolling API | **Mandatory** |
| `RenderApiModule` | Rendering API | **Mandatory** |
| `EventApiModule` | Event API | **Mandatory** |
| `ClientSideRowModelApiModule` | Client-Side Row Model API | **Mandatory** (if using Client-Side Row Model) |
| `ServerSideRowModelApiModule` | Server-Side Row Model API | **Mandatory** (if using Server-Side Row Model) |
---
# AdapTable Features
Canonical page: https://www.adaptabletools.com/docs/getting-started-features-guide
- AdapTable ships a **lot of functionality** - this page is the one place where you can see all of it at a glance
- **New users** evaluating AdapTable can see what's available
- **Developers** can find the specific feature they need, and learn how to leverage it at design-time
- **Run-time users** can learn more about the features they use and which UI controls each one offers
---
# Installing AdapTable for AG Grid
Canonical page: https://www.adaptabletools.com/docs/getting-started-installation
- AdapTable for AG Grid is installed from a public npm registry
- AdapTable supports ESM (preferred) and CJS formats
This page describes how to install the pure TypeScript (i.e. Framework agnostic) version of AdapTable 20.
- See [AdapTable React](https://www.adaptabletools.com/docs/react-installation/index.md), [AdapTable Angular](https://www.adaptabletools.com/docs/angular-installation/index.md) or [AdapTable Vue](https://www.adaptabletools.com/docs/vue-installation/index.md) for framework-related installation instructions
- See [Previous Documentation Versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md#installation) for instructions on installing older versions of AdapTable
## Public npm Registry
AdapTable is installed from a [public npm Registry](https://www.npmjs.com/package/@adaptabletools/adaptable).
### Installing AdapTable
To install AdapTable follow these steps:
These steps assume you are using ESM format and so they reference the ESM packages; see [below](#esm-and-cjs-formats) to learn how to use CommonJS format
Use standard `npm install` commmand.
npm install @adaptabletools/adaptable
For example to use Master-Detail functionality add:
npm install @adaptabletools/adaptable-plugin-master-detail-aggrid
[Plugins](https://www.adaptabletools.com/docs/technical-reference-plugins/index.md) reduce download size by placing less frequently used functionality outside the main download
Install the AG Grid Enterprise package (v.35)
npm install ag-grid-enterprise
If you plan to use AG Grid Charts, or AdapTable's [Sparkline Columns](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md), additionally install the AG Charts package.
npm install ag-charts-enterprise
This is done via the `licenseKey` property in [Adaptable Options](https://www.adaptabletools.com/docs/getting-started-license-key/index.md)
```tsx
const adaptableOptions: AdaptableOptions = {
licenseKey: '',
};
```
## ESM and CJS formats
AdapTable ships with support for both ESM and CJS formats, using 2 parallel sets of packages.
AdapTable **strongly recommends using ESM** wherever possible
- If using ESM, install the "normal" AdapTable packages (e.g. `@adaptabletools/adaptable`)
- If using CommonJS, install the CJS packages (e.g. `@adaptabletools/adaptable-cjs`)
All the CJS packages use the name of the ESM package plus the `-cjs` suffix
| ESM Package | CJS Package |
| ------------------------------------------------------- | ----------------------------------------------------------- |
| `@adaptabletools/adaptable` | `@adaptabletools/adaptable-cjs` |
| `@adaptabletools/adaptable-plugin-interopio` | `@adaptabletools/adaptable-plugin-interopio-cjs` |
| `@adaptabletools/adaptable-plugin-ipushpull` | `@adaptabletools/adaptable-plugin-ipushpull-cjs` |
| `@adaptabletools/adaptable-plugin-master-detail-aggrid` | `@adaptabletools/adaptable-plugin-master-detail-aggrid-cjs` |
| `@adaptabletools/adaptable-plugin-nocode-aggrid` | `@adaptabletools/adaptable-plugin-nocode-aggrid-cjs` |
| `@adaptabletools/adaptable-plugin-openfin` | `@adaptabletools/adaptable-plugin-openfin-cjs` |
See [Using AG Grid Modules & Packages](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) for more detailed information
---
# Integrating AdapTable with AG Grid
Canonical page: https://www.adaptabletools.com/docs/getting-started-integration
- Integrating a non-Framework AdapTable (ie. TypeScript) instance with AG Grid is straightforward
- This page describes the steps required
## Creating an AdapTable Instance
This page shows how to create a "vanilla" AdapTable instance, i.e one that doesn't leverage a Framework.
Like all the demos on this site, the example is in TypeScript (used by most developers using AdapTable).
- For **Framework**-based instructions see [React Integration](https://www.adaptabletools.com/docs/react-integration/index.md), [Angular Integration](https://www.adaptabletools.com/docs/angular-integration/index.md) and [Vue Integration](https://www.adaptabletools.com/docs/vue-integration/index.md)
- See [Previous Documentation Versions](https://www.adaptabletools.com/docs/documentation-previous-versions/index.md#integration) for instructions on integrating **older** versions of AdapTable
- For a pure **JavaScript** example showing how to set up AdapTable see the [vanilla JavaScript AdapTable Template](https://github.com/AdaptableTools/support-template-adaptable-aggrid-vanillajs)
### Detailed Guide to Creating a non-Framework AdapTable Instance (TypeScript)
These are the steps involved in creating a new (vanilla) AdapTable instance:
These 2 `div` elements should be named (ideally in this order):
- _adaptable_ - contains the AdapTable instance
- _grid_ - contains the AG Grid instance (name this 'grid')
```html {3,6}
{/* div for adaptable - always name this 'adaptable' */}
{/* AG Grid container div - use id='grid' */}
```
- Its possible to name the Divs containing AG Grid and AdapTable differently (in place of default values: _grid_ and _adaptable_)
- In this case, provide these names in [`ContainerOptions`](https://www.adaptabletools.com/docs/reference/containeroptions.md) - see [Providing bespoke AdapTable and AG Grid div Ids](https://www.adaptabletools.com/docs/getting-started-setting-adaptable-aggrid-containers/index.md) for more details (also if using a Shadow DOM)
`index.css` contains core styles (and supports both `light` and `dark` themes)
```ts {1}
import '@adaptabletools/adaptable/index.css';
```
- AdapTable's styles use the `adaptable` CSS layer - so you can access that to control specificity
- If your app is using Tailwind, we recommend using this CSS layer order: `@layer theme, base, components, adaptable, utilities`
- See [AdapTable Theming Guide](https://www.adaptabletools.com/docs/handbook-theming/index.md) for full details on choosing and extending AdapTable Themes
Import main `Adaptable` object and any Cell Editors or other required utilities from `@adaptabletools/adaptable`.
Everything is a named export.
```ts
import {
Adaptable,
AdaptableDateEditor,
AdaptableOptions,
AdaptableApi,
InitialState,
AdaptableColumn,
} from '@adaptabletools/adaptable';
```
Import the [AG Grid Enterprise Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md).
```jsx
// Import AG Grid Enterprise Modules
import { Module, AllEnterpriseModule } from 'ag-grid-enterprise';
// Create Modules array (to be passed later to Adaptable Initializer)
export const reqdModules: Module[] = [AllEnterpriseModule];
```
Import the [AG Grid Enterprise Modules](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) including Charts.
Do this if using AG Grid Charts or [AdapTable Sparkline Columns](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md).
```jsx
// Import AG Grid Enterprise Modules
import { Module, AllEnterpriseModule } from 'ag-grid-enterprise';
// Import AG Grid Charts
import { AgChartsEnterpriseModule } from 'ag-charts-enterprise';
// Provide both in the Modules array
export const reqdModules: Module[] = [AllEnterpriseModule.with(AgChartsEnterpriseModule)];
```
Another alternative is to import just the subset of AG Grid Modules that you need to use in your application (given your feature set).
The [AG Grid Modules Reference](https://www.adaptabletools.com/docs/getting-started-aggrid-modules/index.md) contains the **minimum** list of AG Grid Modules required by AdapTable (and those needed by key features)
```jsx
// Import AG Grid Community and Enterprise Modules
import { ClientSideRowModelModule, CsvExportModule } from 'ag-grid-community';
import { Module, ExcelExportModule, MasterDetailModule } from 'ag-grid-enterprise';
// Create Modules array (to be passed later to Adaptable Initializer)
export const reqdModules: Module[] = [
ClientSideRowModelModule,
CsvExportModule,
ExcelExportModule,
MasterDetailModule
// and many more...
];
```
Define and populate a standard [AG Grid GridOptions](https://www.ag-grid.com/javascript-data-grid/grid-interface/#grid-options) object.
Provide all required AG Grid related information including:
- AG Grid theme
- column schema via `ColDefs` (including correct [dell data types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md))
- initial data (if not lazy loading)
- AG Grid events
- any additional, required properties
```ts
const gridOptions: GridOptions = {
theme: themeQuartz,
columnDefs: [
{headerName: 'Make', field: 'make', filter: true, cellDataType: 'text'},
{headerName: 'Model', field: 'model', editable: true, cellDataType: 'text'},
],
rowData: [
{make: 'Toyota', model: 'Yaris', price: 40000},
{make: 'Toyota', model: 'Corolla', price: 28000},
{make: 'Ford', model: 'Mondeo', price: 32000},
],
cellSelection: true,
sideBar: true,
suppressAggFuncInHeader: true,
suppressMenuHide: true,
};
```
- Many ColDef properties are **ignored** by AdapTable and replaced by [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) props - see full details in [Guide to Layouts and ColDefs](https://www.adaptabletools.com/docs/dev-guide-columns-configuring-coldefs/index.md)
- **Do not instantiate AG Grid**; AdapTable will do that itself, together with any required wiring up of objects
- Ensure to always set the appropriate `cellDataType` property in ColumnDefs for each Column that is defined
- This will enable AdapTable to use the correct set of Filters and related properties - see [Setting Cell Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) for more information
Add the [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md) that is required to ship AdapTable with the objects you require for **initial** use.
This will later get merged into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md), together with any changes made by the run-time user.
It **must** include a `Layouts` section, containing at least one [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md).
In this example we do the following:
- Add 2 Pinned Toolbars to the [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md): `Layout` and `Export`
- Created a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) called Cars with 3 columns and Row Grouping for the _Make_ column
- Provided [Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) for 'Price' column of 2 fraction digits and $ sign
- Set a [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) to sort the 'Rating' Column more intuitively
```tsx
const initialState: InitialState = {
Dashboard: {
PinnedToolbars: ['Layout', 'Pricing'],
},
Layout: {
CurrentLayout: 'Cars',
Layouts: [
{
TableColumns: ['Model', 'Price', 'Make'],
RowGroupedColumns: ['Make'],
Name: 'Cars',
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-Price-262',
Scope: {ColumnIds: ['Price']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {FractionDigits: 0, Prefix: '$'},
},
},
],
},
CustomSort: {
CustomSorts: [
{
Name: 'CustomSort-Rating',
ColumnId: 'Rating',
SortedValues: ['AAA', 'AA+'],
},
],
},
} as InitialState;
```
[Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) defines exactly how AdapTable should work.
You should populate this object with:
- a [Primary Key](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md) by defining a Unique Column
- an [Adaptable Id](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md) which will uniquely identify the Grid
- the [License Key](https://www.adaptabletools.com/docs/getting-started-license-key/index.md) provided when purchasing AdapTable
- a [User Name](https://www.adaptabletools.com/docs/getting-started-user-name/index.md) to identify the current user
- implementations of [State Options](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#remote-storage) functions to persist (and reload) [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) remotely
- the `initialState` created above
- any [Plugins](https://www.adaptabletools.com/docs/technical-reference-plugins/index.md) required (e.g. the No Code Plugin)
- any of the other [many options and properties](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) available (where the default values are not appropriate)
- any [Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) (Permissions) required for the User
```tsx
const adaptableOptions: AdaptableOptions = {
licenseKey: '',
primaryKey: 'model',
userName: 'Demo User',
adaptableId: 'Basic Setup',
filterOptions: {
columnFilterOptions: {
manuallyApplyColumnFilter: true,
},
},
initialState: initialState,
plugins: [nocode()],
stateOptions: {
persisteState: {}, // persist State remotely
loadState: {}, // load remotely persisted State
},
};
```
Adaptable Options supports [Typescript Generics](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md#typescript-generics) which ensures a better developer experience by providing the row data type
If the `licenseKey` property is not present, AdapTable will display a watermark and run with reduced functionality
The static asnyc AdapTable constructor receives 2 objects:
- the [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) created in Step 7
- an [`AgGridConfig`](https://www.adaptabletools.com/docs/reference/aggridconfig.md) object which contains two properties:
- the Grid Options object created in Step 5
- the AG Grid Modules defined in Step 4
It returns (via a Promise) an [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) object - which gives run time access to all AdapTable functionality.
```ts {1,6,7}
const agGridConfig: AgGridConfig = {
gridOptions: gridOptions,
agGridModules: reqdModules,
};
const adaptableApi: AdaptableApi = await Adaptable.init(
adaptableOptions,
agGridConfig
);
```
Add a listener to [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) which is fired when AdapTable is initialised.
This should be used to perform any required setup-related actions.
The [`AdaptableReadyInfo`](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md) object provided by the Event, contains two key objects:
- `adaptableApi` which gives access to the [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md)
- `agGridApi` which gives access to [AG Grid's Api](https://www.ag-grid.com/javascript-data-grid/reference/)
```ts {2}
// Subscribe to the Adaptable Ready Event
api.eventApi.on('AdaptableReady', (adaptableReadyInfo: AdaptableReadyInfo) => {
// Use AdapTable API to run a Quick Search
adaptableReadyInfo.adaptableApi.quickSearchApi.runQuickSearch('toy');
// Use AG Grid api to auto size all columns
adaptableReadyInfo.agGridApi.autoSizeAllColumns();
});
```
If you are using TypeScript then you must use version 5.4.5 or higher
See the related articles in this documentation for more detailed instructions on:
- [Choosing a Primary Key](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md)
- [Setting the Adaptable Id](https://www.adaptabletools.com/docs/getting-started-adaptable-id/index.md)
- [Providing a User Name](https://www.adaptabletools.com/docs/getting-started-user-name/index.md)
- [Creating Adaptable Context](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-adaptable-context/index.md)
- [Configuring the Adaptable State Key](https://www.adaptabletools.com/docs/getting-started-adaptable-state-key/index.md)
- [Providing Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md)
- [Managing Remote State Persistence](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-persistence/index.md#remote-storage)
- [Supplying the AdapTable License Key](https://www.adaptabletools.com/docs/getting-started-license-key/index.md)
- [Layouts vs ColDefs](https://www.adaptabletools.com/docs/dev-guide-columns-configuring-coldefs/index.md)
- [Setting Cell Data Types](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md)
- [Listening to Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md)
- [Selecting or Creating an AdapTable Theme](https://www.adaptabletools.com/docs/handbook-theming/index.md)
## Accessing AdapTable at Run-Time
The [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) has many hundreds of methods to allow full, programmatic access to all AdapTable functionality and state at run-time.
It also includes an `eventApi` section for listening to [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md).
## Destroying AdapTable
It is possible to programmatically destroy - and clean up - an AdapTable session.
This is done by using the `destroy` function, available in the root of [`Adaptable API`](https://www.adaptabletools.com/docs/reference/adaptableapi.md#destroy).
- This function is only needed for the vanilla version of AdapTable
- All 3 Framework wrappers handle unmount and cleanup as part of the application lifecycle
The function performs 2 important actions:
- unmounts the Adaptable component
- destroys the AG Grid instance.
**AG Grid is not instantiating even though I passed in Grid Options?**
Make sure that you also provide AG Grid Modules; since AG Grid v.30 they are mandatory for AG Grid to instantiate.
**Why am I seeing a warning that AdapTable doesn't know the type of the column?**
This happens because AG Grid has no means of setting the DataType of the column, so AdapTable has to guess it by looking at the first row in the grid.
You can avoid this by providing each Column with a [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) property when configuring GridOptions.
**Why is AdapTable not showing up in my browser? I'm using Internet Explorer.**
AdapTable no longer supports Internet Explorer.
It is **guaranteed** to work in Chromium browsers (e.g. Chrome, Edge, Opera etc.).
AdapTable is compatible with other browsers like Firefox, Safari etc. but we cannot guarantee every part of every feature will be fully available to the same extent as in Chromium browsers.
**Why do I see an error message saying there `There is no DIV with id=[Name] so cannot render Adaptable`?**
You have likely supplied a bespoke value for the `adaptableContainer` property in [Container Options](https://www.adaptabletools.com/docs/getting-started-setting-adaptable-aggrid-containers/index.md) but not provided a Div with the same name.
**Can I remove the loading message that appears?**
Yes, this is possible by setting `showLoadingScreen` to false in `loadingScreenOptions` section of [User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md)
**I am using Stencil and cannot see AdapTable?**
[Stencil](https://stenciljs.com/) uses a shadow DOM, so you need to specify the `agGridContainer` and `adaptableContainer` in `adaptableOptions.containerOptions` as elements, not as strings.
If you have `scoped: true` then use:
```
this.el.shadowRoot.querySelector(...)
```
to retrieve references to your vendor grid & adaptable container elements.
If you have `scoped: false` you should use:
```
this.el.querySelector(...)
```
---
# AdapTable - Key Concepts
Canonical page: https://www.adaptabletools.com/docs/getting-started-key-concepts
- When developing with AdapTable there are 3 basic concepts to understand:
- **Adaptable Options** — how to configure your AdapTable instance
- **Initial Adaptable State** — the objects you provide to your application for first-time use
- **Adaptable API** — how to access AdapTable at run-time
## The 3 Main Classes
The three classes below are key to getting started and making AdapTable work for you.
### Adaptable Options
Adaptable Options is a large group of property options which you **configure at design-time**.
This allows you to set up AdapTable so that it fits the requirements of the containing application.
The available properties include the the `adaptableId` and many groups of related options (e.g. Entitlements, Layout, Search, Edit, Menu etc.)
- Many of the options are JavaScript functions which, if provided, AdapTable will invoke when required
- Adaptable Options also includes the underlying [Initial Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md)
Learn more about the options available in [Adaptable Options Reference](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md)
### Initial Adaptable State
Initial State is a group of objects written in JSON that you will **define at Design Time**.
Most Initial State is optional but the `Layout` section (with at least one [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) defined) is mandatory
It includes all the AdapTable Objects required for initial use of your hosted application e.g. Layouts, Filters, Reports, Alerts, Format Columns etc.
- Adaptable Initial State contains persistable objects and properties which **can change during Application run-time**
- Adaptable Options contains behaviour and functionality that **will never change** post-creation
When an application starts for the first time, Initial Adaptable State is loaded, and then merged with any run-time changes effected by the user; which is then stored (and subsequently reloaded) as [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
Learn how Initial State works in greater detail in [Guide to using Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) and the [Initial State Reference](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md)
### Adaptable API
The [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) provides full, rich, programmatic, **run-time access** to all AdapTable functionality.
This allows you to access [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) in a 'safe' manner.
Anything that is achievable in the AdapTable UI can be accomplised alternatively using the Adaptable API.
Indeed you can use Adaptable API connect to AdapTable's functionality via your own custom screens bypassing AdapTable's UI altogether
See the full contents of the Adaptable API in [Technical Reference](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md)
### Fitting It Together
These 3 concepts are linked together when AdapTable is [instantiated](https://www.adaptabletools.com/docs/getting-started-integration/index.md).
The first two steps - creating **Adaptable Options** and providing **Initial Adaptable State** - are identical across all four variants of AdapTable.
Only the final step differs: each framework has its own mechanism for creating AdapTable and tying it in with AG Grid, but all provide a handle to the same **Adaptable API**.
### Fitting these 3 Key Concepts Together
**Adaptable Options** contains a large group of properties and classes.
It is required by all four framework versions to initialise and configure AdapTable.
```ts {1}
const adaptableOptions: AdaptableOptions = {
licenseKey: '', // license key you were given
primaryKey: 'tradeId', // a unique column
adaptableId: 'trading_app', // a unique grid id
filterOptions: { clearFiltersOnStartUp: true }, // configurable options
initialState: initialState, // Inital Adaptable State required
};
```
Adaptable Options includes **Initial Adaptable State** as a mandatory property.
This must include a Layout, and in every real-world use case, additional objects.
```ts {1}
const initialState: InitialState = {
Dashboard: {
Tabs: [{ Name: 'Grid', Toolbars: ['Layout', 'Pricing']}],
},
Layout: {
CurrentLayout: 'Cars',
Layouts: [
{
TableColumns: ['Model', 'Price', 'Make'],
RowGroupedColumns: ['Make'],
Name: 'Cars',
},
],
},
} as InitialState;
```
### Vanilla
In the **Vanilla** (TypeScript) version, the static async `Adaptable.init` constructor receives the Adaptable Options and an [`AgGridConfig`](https://www.adaptabletools.com/docs/reference/aggridconfig.md) object.
It returns (via a Promise) the **Adaptable API** object which gives full run-time access to all AdapTable functionality.
```ts {6}
const agGridConfig: AgGridConfig = {
gridOptions, // AG Grid GridOptions object
agGridModules, // AG Grid Modules required
};
const adaptableApi: AdaptableApi = await Adaptable.init(adaptableOptions, agGridConfig);
```
### React
In **AdapTable React** you render the `Adaptable.Provider` component (passing Adaptable Options, Grid Options and AG Grid Modules).
Obtain the **Adaptable API** from the `adaptableReady` callback, which receives an [`AdaptableReadyInfo`](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md) object.
```jsx {5-7}
{
// adaptableApi gives full run-time access to AdapTable
}}
>
```
### Angular
In **AdapTable Angular** you render the `` component and bind to its `(adaptableReady)` output.
The handler receives an [`AdaptableReadyInfo`](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md) object which contains the **Adaptable API**.
```html {5,15}
export class AppComponent {
adaptableReady = ({ adaptableApi }: AdaptableReadyInfo) => {
// adaptableApi gives full run-time access to AdapTable
};
}
```
### Vue
In **AdapTable Vue** you render the `AdaptableProvider` component and listen to its `onAdaptableReady` event.
The event provides an [`AdaptableReadyInfo`](https://www.adaptabletools.com/docs/reference/adaptablereadyinfo.md) object which contains the **Adaptable API**.
```vue {5-9}
{
// adaptableApi gives full run-time access to AdapTable
}
"
>
```
- [Modules](https://www.adaptabletools.com/docs/technical-reference-adaptable-modules/index.md), [Plugins](https://www.adaptabletools.com/docs/technical-reference-plugins/index.md), [Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md), [Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md), [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md), [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) and [Logging](https://www.adaptabletools.com/docs/dev-guide-support-logging/index.md) each have their own dedicated guides
---
# Supplying the License Key
Canonical page: https://www.adaptabletools.com/docs/getting-started-license-key
- The License Key will validate that you are using an authorised version of AdapTable
To use AdapTable in a commercial application you must have a valid [License](https://www.adaptabletools.com/buy/buying-adaptable-licensing).
This take the form of an alphanumeric **License Key** which is provided by the AdapTable Tools Team.
When AdapTable loads, it checks whether the key is present and correct.
Information provided in the license key includes:
- licence start and end dates
- name of the company awarded the license
- type of [Application License](https://www.adaptabletools.com/buy/buying-adaptable-licensing#application-licenses) (Single or Multiple)
- type of [Package](https://www.adaptabletools.com/buy/buying-adaptable-licensing#license-packages) (Premium or Enterprise)
- name of the licensed application (if using a [Single Application License](https://www.adaptabletools.com/buy/buying-adaptable-licensing#single-application-license))
If the license key is not present, AdapTable will display a watermark and run with reduced functionality
You will use this key as the value for the mandatory `licenseKey` property in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
- See [Integrating AdapTable](https://www.adaptabletools.com/docs/getting-started-installation/index.md) for details on how to provide Adaptable Options in your application
- There are separate instructions for [AdapTable React](https://www.adaptabletools.com/docs/react-integration/index.md), [AdapTable Angular](https://www.adaptabletools.com/docs/angular-integration/index.md) and [AdapTable Vue](https://www.adaptabletools.com/docs/vue-integration/index.md) integrations
### `licenseKey`
Commercial License Key provided by AdapTable Tools Support
Sets the AdapTable License Key.
This is a mandatory property
```ts {2}
const adaptableOptions: AdaptableOptions = {
licenseKey:
}
```
---
# Understanding Primary Keys
Canonical page: https://www.adaptabletools.com/docs/getting-started-primary-key
- A Primary Key is required by AdapTable for cell identification purposes
- It is the Id of a Column with guaranteed unique, unchanging values
- If it cannot be provided, then an autogenerated key is used (but we strongly recommend that users provide one)
## Primary Key Column
The Primary Key is set via the (mandatory) `primaryKey` property in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
The value provided should either be:
- an AG Grid Column - either the `colId` or `field` property
The column does not need to be visible but it does need to be specified
- available as a data property in AG Grid's data source
- Without a Primary Key, AdapTable would not be able to uniquely identify cells for [Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising/index.md) or [Editing](https://www.adaptabletools.com/docs/handbook-editing/index.md)
- Nor could it exactly specify in the [Cell Changed](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md) or [Adaptable State Changed](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-events/index.md) Events which cells have been updated
### `primaryKey`
Name of a Column in the Data Source guaranteed to contain unique values
It is highly recommended that this is provided.
The value provided does not need to be a column in the grid but must be in the data source.
If you absolutely cannot provide one, then leave blank and set `autogeneratePrimaryKey` to true.
```ts {2}
const adaptableOptions: AdaptableOptions = {
primaryKey: 'tradeId',
};
```
### Key Uniqueness
It is important that Primary Key Column is one which **guarantees to contain unique values**.
### Why do Primary Keys have to be Unique?
There are a few reasons why Primary Keys must be unique.
Perhaps the most important consideration is that if the `getRowId` property hasn't been provided in AG Grid's `GridOptions`, AdapTable will supply one using the Primary Key value.
Having a Primary Key column with duplicate values will result in duplicate or inconsistent indexing.
Additionally row selection in both [AG Grid](https://ag-grid.com/javascript-data-grid/viewport/#selection) and [AdapTable](https://www.adaptabletools.com/docs/handbook-selecting/index.md) is predicated on unique row keys.
### Key Immutability
It is also important that values in the Primary Key Column do not change during the lifetime of the Application.
### Why do Primary Keys have to be Immutable?
Many things in AdapTable are stored using the Primary Key.
This includes objects, like Notes, which are stored between Sessions, and objects which are stored during a Session (e.g. which cells are flashing).
If a Primary Key changes once its been created, it will not be possible to identify these objects any longer.
### Displaying Warnings
AdapTable logs a `warning` message to the console if the Primary Key provided is not an AG Grid Column.
You can remove this warning by setting `showMissingColumnsWarning` to _false_ in [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md)
### `showMissingColumnsWarning`
Log warning to console if AdapTable cannot find a column
AdapTable, by default, logs a warning to the Console whenever a column referenced in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) or [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) does not exist.
Set this property to _false_ to suppress this warning.
```ts {4}
// Don't display any warning messages in the Console if a referenced Column doesnt exist
const adaptableOptions: AdaptableOptions = {
alertOptions: {
showMissingColumnsWarning: false,
},
};
```
This is particularly useful if the Primary Key value is provided in the Data Source but is not an AG Grid column.
- For additional security you can also set `showMissingPrimaryKeyAlert` to _true_ in [Alert Options](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md#warnings)
- This displays an [Alert](https://www.adaptabletools.com/docs/handbook-alerting/index.md) (with a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)) when no column in the grid which matches the Primary Key value
### `showMissingPrimaryKeyAlert`
Shows Alert if Primary Key column is not present or incorrect
This property will cause AdapTable to display an Alert if the Primary Key column in Adaptable Options is missing or wrongly applied.
```ts {4}
// Shows Alert if Primary Key column in Adaptable Options is not present or incorrect
const adaptableOptions: AdaptableOptions = {
alertOptions: {
showMissingPrimaryKeyAlert: true,
},
};
```
## Auto Generated Key
If it is absolutely not possible to provide a Primary Key column of your own, AdapTable can auto-generate one.
- Only use this option as a **last resort** if there is no column with unique values, as there are [siginficant limitations](#limitations)
- Auto-generated Keys cannot be used in Modules (e.g. Free Text Columns) which store cell details between sessions
Simply set `autogeneratePrimaryKey` property to _true_ in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) and AdapTable will create - and manage - its own internal Primary Key.
### `autogeneratePrimaryKey`
Request AdapTable to create a generated Primary Key
Sets whether Adaptable should dynamically generate the Primary Key instead of using the `primaryKey` property.
If setting this property to _true_, ensure also to set `primaryKey` to an empty string
```ts {2,3}
const adaptableOptions: AdaptableOptions = {
autogeneratePrimaryKey: true,
primaryKey: '',
};
```
### Limitations
There are a few important limitations when using an auto generated Primary Key:
- Modules which require persistable, consistent Primary Key values to save data are not available, including:
- [Free Text Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md)
- [Notes](https://www.adaptabletools.com/docs/handbook-notes/index.md)
- [Comments](https://www.adaptabletools.com/docs/handbook-comments/index.md)
- Live Data updates **from** Excel back to AdapTable (when using [OpenFin](https://www.adaptabletools.com/docs/integrations-openfin/index.md)) will not work (as Excel needs the column to be in the exported data)
- If using an auto-generated key, the **only safe way** to [load grid data](https://www.adaptabletools.com/docs/handbook-managing-grid-data-loading/index.md), [add Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-add/index.md)or [Update Grid Rows](https://www.adaptabletools.com/docs/handbook-managing-grid-data-rows-update/index.md) is through AdapTable's [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md); only use the following methods for any data manipulation you require:
- `loadGridData` - for initial (and replacement) data load
- `addGridData` - to add new rows
- `updateGridData` - to update rows
- `deleteGridData` - to remove rows
- This restriction is required because AdapTable needs to intercept all data-related methods
- This will safely ensure that Primary Keys are propertly created and then kept correctly updated
### Using an auto generated Primary Key
Using an auto generated Primary Key - if it is absolutely necessary to do so - requires a couple of changes in the AdapTable setup:
There are 2 main changes that need to be made when setting up Adaptable Options:
- provide no value to the `primaryKey` value
- set the `autogeneratePrimaryKey` property to **true**
```ts {2,5}
const adaptableOptions: AdaptableOptions = {
primaryKey: '', // set empty key
userName: 'Demo User',
adaptableId: 'Basic Setup',
autogeneratePrimaryKey: true, // auto-generate key
initialState: initialState,
};
```
When you are using an auto generated Primary Key you need to provide row data via methods contained in [Grid Api](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)
```ts {2}
// Update the Grid Data using the Adaptable API
adaptableApi.gridApi.updateGridData([changedRow]);
```
**Example: Auto-Generated Primary Keys**
Using Primary Keys dynamically generated by AdapTable
- This Demo uses an Auto Generated Primary Key
- It also has a Custom Button which updates the Price in the First Row - using the `updateGridData` function in [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)
### Expand to see how this was created
```ts
export const adaptableOptions: AdaptableOptions = {
primaryKey: '',
adaptableId: 'Auto Generated Primary Key',
autogeneratePrimaryKey: true,
};
```
- Open the Settings Panel and note that the Notes, Comments and FreeText Column Modules are not visible
```ts
import {
AdaptableButton,
AdaptableOptions,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {IRowNode} from 'ag-grid-enterprise';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: '',
adaptableId: 'Auto Generated Primary Key',
autogeneratePrimaryKey: true,
dashboardOptions: {
customToolbars: [
{
name: 'Custom',
title: 'Custom',
toolbarButtons: [
{
label: 'Increase First Row "Rating"',
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const firstNode: IRowNode | undefined =
context.adaptableApi.gridApi.getFirstRowNode();
let firstRow = firstNode?.data;
let firstRowRating = firstRow['Rating'];
const newRating =
firstRowRating + Math.floor(Math.random() * 10) + 1;
firstRow['Rating'] = newRating;
// update Adaptable using Grid Api
context.adaptableApi.gridApi.updateGridData([firstRow]);
},
},
],
},
],
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Demo',
Toolbars: ['Custom'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
headerName: 'Name',
field: 'Name',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Rating',
field: 'Rating',
filter: true,
editable: false,
sortable: true,
cellDataType: 'number',
},
{
headerName: 'Year',
field: 'Year',
filter: true,
editable: false,
sortable: true,
cellDataType: 'number',
},
{
headerName: 'Institutions',
field: 'Institutions',
filter: true,
editable: false,
sortable: true,
cellDataType: 'textArray',
},
{
headerName: 'Country',
field: 'Country',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'CountryCode',
field: 'CountryCode',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Email',
field: 'Email',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
];
```
```ts
export const rowData = [
{
Name: 'Giorgio Parisi',
Year: 2021,
Institutions: ['Sapienza', ' Columbia'],
Country: 'Italy',
CountryCode: 'ITA',
Email: 'giorgio.parisi@mail.com',
Rating: 89,
},
{
Name: 'Klaus Hasselman',
Year: 2021,
Institutions: ['Hamburg', 'Max Planxk', 'Uni of California'],
Country: 'Germany',
CountryCode: 'DEU',
Email: 'klaus.hasselman@yahoo.com',
Rating: 74,
},
{
Name: 'Syukor Manabe',
Year: 2021,
Institutions: ['Princeton', 'Nagoya'],
Country: 'Japan',
CountryCode: 'JPN',
Email: 'syukor.manabe@outlook.com',
Rating: 92,
},
{
Name: 'Andrea Ghez',
Year: 2020,
Institutions: ['Uni of California'],
Country: 'United States',
CountryCode: 'USA',
Email: 'andrea.ghez@mail.com',
Rating: 85,
},
{
Name: 'Reinhard Genzel',
Year: 2020,
Institutions: ['Max Planck'],
Country: 'Germany',
CountryCode: 'DEU',
Email: 'reinhard.genzel@mail.com',
Rating: 68,
},
{
Name: 'Roger Penrose',
Year: 2020,
Institutions: ['Columbia', 'Princeton', 'Syracuse'],
Country: 'United Kingdom',
CountryCode: 'GBR',
Email: 'roger.penrose@yahoo.com',
Rating: 71,
},
{
Name: 'Didier Queloz',
Year: 2019,
Institutions: ['University of Cambridge', 'Geneva'],
Country: 'Switzerland',
CountryCode: 'CHE',
Email: 'didier.queloz@mail.com',
Rating: 87,
},
{
Name: 'Michel Mayor',
Year: 2019,
Institutions: ['Geneva', 'Columbia'],
Country: 'Switzerland',
CountryCode: 'CHE',
Email: 'michel.mayor@yahoo.com',
Rating: 94,
},
{
Name: 'Jim Peebles',
Year: 2019,
Institutions: ['Princeton'],
Country: 'United States',
CountryCode: 'USA',
Email: 'jim.peebles@outlook.com',
Rating: 66,
},
];
```
---
# AdapTable and AG Grid Div Elements
Canonical page: https://www.adaptabletools.com/docs/getting-started-setting-adaptable-aggrid-containers
- By default AdapTable assumes that developers will provide Divs of 'adaptable' and 'grid'
- However, developers can configure custom Div elements to display AdapTable and AG Grid
- These are only required when using AdapTable vanilla (i.e. not a framework version)
- These are configured using the ContainerOptions section of AdapTable Options
The [`ContainerOptions`](https://www.adaptabletools.com/docs/reference/containeroptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) contains a series of properties relating to various Div elements that can be used in Adaptable.
Two of these are of particular importance when initialising AdapTable (in the vanilla / TypeScript version):
- `adaptableContainer`
- `agGridContainer`
These are **not required** if using [AdapTable React](https://www.adaptabletools.com/docs/index.md), [AdapTable Angular](https://www.adaptabletools.com/docs/index.md) or [AdapTable Vue](https://www.adaptabletools.com/docs/index.md) as they each work differently
Both these properties allow the associated container to be provided in one of 4 ways:
- `string` — an element ID (resolved via `document.getElementById`)
- `AdaptableCssSelector` — a CSS selector (resolved via `document.querySelector`)
- `HTMLElement` — a direct reference to a DOM element
- a JavaScript function which returns any one of the above
## AdapTable Container
By default AdapTable should be provided in a Div with the Id of 'adaptable'.
If the default value is not used for this Div, then the bespoke Id of the div needs to be supplied using the `adaptableContainer` property.
- Make sure if you provide an implementation for this property to supply a Div with the same name
- If not supplied, you will see this error: `There is no DIV with id=[Name] so cannot render Adaptable`
### `adaptableContainer`
Div which contains AdapTable instance (AdapTable vanilla only)
[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)
Name of the Div which contains the AdapTable instance (used in AdapTable vanilla version only).
The property returns an [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md) value either directly or via a function:
```ts
adaptableContainer?: | AdaptableContainerValue | ((context: InitContainerContext) => AdaptableContainerValue);
```
The [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md) can be one of the 3 values:
- `string` — an element ID (resolved via `document.getElementById`)
- `AdaptableCSSSelector` — a CSS selector (resolved via `document.querySelector`)
- `HTMLElement` — a direct reference to a DOM element
If using a function, the property receives context of type [`InitContainerContext`](https://www.adaptabletools.com/docs/reference/initcontainercontext.md) which is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/initcontainercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
| [adaptableId](https://www.adaptabletools.com/docs/reference/initcontainercontext.md#adaptableid) | `string` | Id of current AdapTable instance |
| [adaptableStateKey](https://www.adaptabletools.com/docs/reference/initcontainercontext.md#adaptablestatekey) | `string` | Current Adaptable State Key |
This is invoked **before** AdapTable initialises, so unlike most Context classes it does not contain the AdapTable API
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
adaptableContainer: 'myAdapTableContainer'
}
}
```
## AG Grid Container
By default AG Grid should be provided in a Div with the Id of 'grid'.
If the default value is not used for this Div, then the bespoke Id of the Div needs to be supplied using the `agGridContainer` property.
### `agGridContainer`
Div which contains AG Grid instance (AdapTable vanilla only)
[`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md)
Name of the Div which contains the AG Grid instance (used in AdapTable vanilla version only).
The property returns an [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md) value either directly or via a function:
```ts
agGridContainer?: | AdaptableContainerValue | ((context: InitContainerContext) => AdaptableContainerValue);
```
The [`AdaptableContainerValue`](https://www.adaptabletools.com/docs/reference/adaptablecontainervalue.md) can be one of the 3 values:
- `string` — an element ID (resolved via `document.getElementById`)
- `AdaptableCSSSelector` — a CSS selector (resolved via `document.querySelector`)
- `HTMLElement` — a direct reference to a DOM element
If using a function, the property receives context of type [`InitContainerContext`](https://www.adaptabletools.com/docs/reference/initcontainercontext.md) which is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/initcontainercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
| [adaptableId](https://www.adaptabletools.com/docs/reference/initcontainercontext.md#adaptableid) | `string` | Id of current AdapTable instance |
| [adaptableStateKey](https://www.adaptabletools.com/docs/reference/initcontainercontext.md#adaptablestatekey) | `string` | Current Adaptable State Key |
This is invoked **before** AdapTable initialises, so unlike most Context classes it does not contain the AdapTable API
```ts {3}
const adaptableOptions: AdaptableOptions = {
containerOptions: {
agGridContainer: 'myAGGridContainer'
}
}
```
### Using a Shadow DOM
If using a package like stencil which uses a shadow DOM, `agGridContainer` and `adaptableContainer` should be specified as elements, rather than strings.
If `scoped: true` is set, then to retrieve references to vendor grid and adaptable container elements, use:
```
this.el.shadowRoot.querySelector(...)
```
If `scoped: false` is set, then it should be:
```
this.el.querySelector(...)
```
So the resulting code might look like this:
```ts
containerOptions.agGridContainer = this.el.querySelector('#grid')
containerOptions.adaptableContainer = this.el.querySelector('#adaptable')
```
---
# Providing a User Name
Canonical page: https://www.adaptabletools.com/docs/getting-started-user-name
- The `userName` property in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) uniquely idenfies the user of the current instance
The `userName` property allows you to uniquely identify the current user.
The property is set in the root of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md).
### `userName`
Name of current AdapTable user
Set this to the name of the current AdapTable user.
```ts {2}
const adaptableOptions: AdaptableOptions = {
userName: 'John Smith',
}
```
## Base Context
- The value of the `userName` property is suppled in the very commonly used [`Base Context`](https://www.adaptabletools.com/docs/reference/basecontext.md); this is the base of the `xxxContext` properties supplied to most functions in [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md), and also the base of the `xxxEventInfo` object included in all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md)
---
# What's New in AdapTable
Canonical page: https://www.adaptabletools.com/docs/getting-started-whats-new
---
# Action Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-action-column
- AdapTable allows developers to define Action Columns which are:
- Special columns that contain customisable buttons for performing bespoke row-based actions
- The button is an Adaptable Button which is very flexible and configurable
- Multiple Buttons can be displayed as required
- Alternatively a dropdown can be rendered which contains multiple buttons in a menu
Action Columns are special columns which display a Button (or Buttons) with a user-defined action.
The Button can be styled and configured in many ways. It is defined by developers at **design-time** and rendered by AdapTable at **run-time**.
As an alternative to a Button a Dropdown can be displayed with multiple menu-like items.
- Buttons (and / or dropdowns) can be provided with [Action Column Commands](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md)
- These are designed for very common use cases, e.g. `edit`, `delete`, `clone`
Action Columns do not exist in the underlying AG Grid data source but are still stored with [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
- Action Columns - like [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [Free Text Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) - are not "normal" data columns
- Instead they are **created dynamically** by AdapTable each time the Application runs
- By contrast [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) are "normal" data columns, albeit ones which AdapTable specially renders
Once created, Action Columns can be used and managed like any other Column in AG Grid and AdapTable.
Action Columns can't be created, edited or deleted in AdapTable UI, but can be moved, hidden, or added to a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md)
**Example: Action Columns: Usage**
How to define Action Columns
- In this example we define 2 Action Columns:
- `Update Stars`
- renders a single button which increments or decrements `Github Stars` Column, with logic to change the text, style, visibility and disabled state of the button
- `label` and `buttonStyle` both change based on whether the `Language` is _JavaScript_
- `hidden` when the `Name` is _stencil_ or _polymer_
- `disabled` if fewer than 200 `Github Watchers`
- `TS`
- renders a button which opens the TypeScript documentation
- `hidden` when the `Language` is not _TypeScript_
- contains **only** an icon (and no visible button style)
```ts
import {
AdaptableOptions,
ActionColumnContext,
AdaptableButton,
CellUpdateRequest,
ActionColumnButton,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Action Columns Basic',
actionColumnOptions: {
actionColumns: [
{
columnId: 'update_stars',
friendlyName: 'Update Stars',
actionColumnSettings: {
suppressMenu: true,
resizable: false,
},
actionColumnButton: {
label: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
return context.rowNode?.data?.language === 'JavaScript'
? 'Add Star'
: 'Remove Star';
},
buttonStyle: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
return context.rowNode?.data?.language === 'JavaScript'
? {
variant: 'raised',
tone: 'accent',
}
: {
variant: 'raised',
tone: 'success',
};
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
let increment =
context.rowNode?.data?.language === 'JavaScript' ? 1 : -1;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: rowData.github_stars + increment,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
hidden: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
return (
context.rowNode?.data?.name === 'stencil' ||
context.rowNode?.data?.name === 'polymer'
);
},
disabled: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
return context.rowNode?.data?.github_watchers < 200;
},
},
},
{
columnId: 'more_typescript',
friendlyName: 'TS',
actionColumnSettings: {
suppressMenu: true,
suppressMovable: true,
resizable: false,
},
actionColumnButton: {
icon: {
style: {height: 20, width: 20},
src: 'https://upload.wikimedia.org/wikipedia/commons/4/4c/Typescript_logo_2020.svg',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
Object.assign(document.createElement('a'), {
target: '_blank',
href: 'https://www.typescriptlang.org/',
}).click();
},
hidden: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
return context.rowNode?.data?.language !== 'TypeScript';
},
},
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'update_stars',
'week_issue_change',
'github_watchers',
'language',
'more_typescript',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## AdapTable Buttons
Action Columns are essentially powerful wrappers around [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md).
AdapTable Buttons have many properties (most available also as functions) which provide full control over:
- the Button's text
- how the Button looks
- an optional icon
- whether or not the Button is visible in a given row
- whether or not the Button is disabled in a given row
- what happens when the Button is clicked
### How Action Columns Work in AdapTable
Each time the application starts, AdapTable retrieves the details of any Action Columns from [User Interface Options](https://www.adaptabletools.com/docs/ui-technical-reference/index.md).
For each Action Column definition, AdapTable will:
1. Create an [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md)
2. Create an equivalent [AG Grid column](https://www.ag-grid.com/javascript-data-grid/column-definitions/)
- For advanced use cases it is possible to define the Action Column in AG Grid Column Definitions
- The Columns is "wired up" to AdapTable by using [Specialised Column Types](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md#special-columns)
### Multiple Buttons
An Action Column can contain more than one button if required.
There is no limit on the number of Buttons in an Action Column
**Example: Action Columns: Multiple Buttons**
Action Columns with multiple Buttons
- In this example we define 2 Action Columns, that each contains 2 buttons:
- `Update Issues`: contains `Up` and `Down` buttons that increment / decrement the `Issue Change` column respectively
- `Manage Row`: contains `Add` and `Delete` buttons to add / delete Rows (and is pinned to the right in the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md))
- Note: The same functionality could be achieved in the first Action Column by using [Plus Minus](https://www.adaptabletools.com/docs/handbook-editing-plus-minus/index.md) and for the second by using Action Column Commands
```ts
import {
AdaptableOptions,
ActionColumnContext,
AdaptableButton,
CellUpdateRequest,
ActionColumnButton,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Action Columns Multiple Buttons',
actionColumnOptions: {
actionColumns: [
{
columnId: 'update_issues',
friendlyName: 'Update Issues',
actionColumnButton: [
{
label: 'Up',
buttonStyle: {
variant: 'outlined',
tone: 'info',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'week_issue_change',
newValue: rowData.week_issue_change + 1,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
},
{
label: 'Down',
buttonStyle: {
variant: 'outlined',
tone: 'warning',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'week_issue_change',
newValue: rowData.week_issue_change - 1,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
},
],
},
{
columnId: 'manage_row',
friendlyName: 'Manage Row',
actionColumnButton: [
{
label: 'Add',
buttonStyle: {
variant: 'raised',
tone: 'neutral',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
context.adaptableApi.rowFormApi.displayCreateRowForm();
},
},
{
label: 'Delete',
buttonStyle: {
variant: 'outlined',
tone: 'neutral',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
context.adaptableApi.gridApi.deleteGridData([
context.rowNode?.data,
]);
},
},
],
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'week_issue_change',
'update_issues',
'github_watchers',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'topics',
'description',
'manage_row',
],
ColumnPinning: {manage_row: 'right'},
AutoSizeColumns: true,
},
],
},
},
};
```
## Column width
Use `actionColumnSettings` to control how wide the column is:
| Property | Purpose |
| ----------- | ------------------------------------------------------------------------------ |
| `width` | Fixed width in pixels (overrides `autoWidth` and `minWidth`) |
| `minWidth` | Minimum width; also used as the column width when `autoWidth` is false |
| `autoWidth` | Estimates width from button labels/icons (or the dropdown label) at setup time |
- `autoWidth` uses **static** labels and icons only. If `label`, `icon`, `hidden`, or `disabled` are functions, set `width` explicitly.
- Layout `AutoSizeColumns` does not replace action-column width calculation — configure the action column directly.
## Button layout
### Icon position
Set `iconPosition` on any [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) inside an action column:
```ts
{
label: 'Forward',
iconPosition: 'end', // label before icon (default is 'start')
icon: { name: 'arrow-right' },
onClick: (button, context) => { /* ... */ },
}
```
## Dropdown mode
Action Columns can also contain a dropdown (instead of a button).
This is useful when several actions would crowd the row; all buttons appear in a single menu.
Dropdown mode is activated by setting `displayMode` to 'dropdown'
```ts {2}
actionColumnSettings: {
displayMode: 'dropdown',
dropdownLabel: 'Manage',
},
actionColumnButton: [
//add buttons here as normal and they will appear in a menu
],
```
The rules which AdapTable sets for which properties are applied in dropdown mode are as follows:
| Property | Trigger button (`dropdownLabel`) | Menu items (each `actionColumnButton`) |
| --------------------- | ------------------------------------------- | --------------------------------------- |
| `label` | Yes — trigger text | Yes — row text |
| `icon` | No | Yes — icon column (left of label) |
| `tooltip` | No | Used as fallback if `label` is empty |
| `onClick` / `command` | No | Yes |
| `hidden` / `disabled` | No | Yes |
| `buttonStyle` | **No** — only uses `outlined` / `neutral` | **No** |
| `iconPosition` | **No** — chevron always after trigger label | **No** — menu is always icon then label |
- `buttonStyle` and `iconPosition` on individual buttons only take effect when `displayMode` is `'buttons'`
- In dropdown mode, styling is deliberately uniform: one trigger plus a standard list
**Example: Action Columns: Dropdown**
Action column with dropdown menu
- This example contains 2 Action Columns that render in Dropdown Mode:
- `Update Change` opens a menu with increment and decrement actions (that work on the `Issue Change` column)
- `Manage` opens a menu with edit, and delete action column commands
```ts
import {
ActionColumnButton,
ActionColumnContext,
AdaptableOptions,
CellUpdateRequest,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Action Columns Dropdown',
actionColumnOptions: {
actionColumns: [
{
columnId: 'update_change',
friendlyName: 'Update Change',
actionColumnSettings: {
displayMode: 'dropdown',
dropdownLabel: 'Change',
autoWidth: true,
minWidth: 110,
},
actionColumnButton: [
{
label: 'Increment',
icon: {name: 'plus'},
onClick: (
_button: ActionColumnButton,
context: ActionColumnContext
) => {
const rowData = context.rowNode?.data as WebFramework;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'week_issue_change',
newValue: rowData.week_issue_change + 1,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
},
{
label: 'Decrement',
icon: {name: 'minus'},
onClick: (
_button: ActionColumnButton,
context: ActionColumnContext
) => {
const rowData = context.rowNode?.data as WebFramework;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'week_issue_change',
newValue: rowData.week_issue_change - 1,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
},
],
},
{
columnId: 'row_actions',
friendlyName: 'Actions',
actionColumnSettings: {
displayMode: 'dropdown',
dropdownLabel: 'Manage',
autoWidth: true,
minWidth: 110,
},
actionColumnButton: [
{
command: 'edit',
},
{
command: 'delete',
},
],
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'week_issue_change',
'update_change',
'language',
'license',
'row_actions',
],
ColumnPinning: {row_actions: 'right'},
AutoSizeColumns: true,
},
],
},
},
};
```
## Leveraging Action Columns
AdapTable automatically creates Action Columns in 2 additional use cases:
- when using [FDC3](https://www.adaptabletools.com/docs/handbook-fdc3/index.md) to make it easy to raise Intents and broadcast Contexts
- if adding [Action Buttons](https://www.adaptabletools.com/docs/handbook-monitoring-data-change-history-buttons/index.md) to the Data Change History Monitor
---
# Action Column Command Buttons
Canonical page: https://www.adaptabletools.com/docs/handbook-action-column-command
- Action Column Buttons can display dedicated Commands to handle the most frequent use cases
- Most of these leverage the [Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md) when clicked
Action Column Buttons can be provided with a **Command** as an alternative to wiring up `onClick`.
These are designed to cater for the most common use cases, to reduce development overhead
AdapTable provides 4 Action Column Commands:
| Command | Action when Clicked |
| -------- | ---------------------------------------------------------------------------------------------------------- |
| `create` | Opens the [Create Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md#create-row-form) |
| `clone` | Opens the [Clone Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md#clone-row-form) |
| `edit` | Opens the [Edit Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md#edit-row-form) |
| `delete` | Triggers the (non-visible) [Delete Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md#delete-row-form) |
**Example: Action Column Commands**
Using Action Column Commands
- This demo includes an Action Column (named `Actions`) which contains 3 buttons that are configured with Action Column Commands:
- `Clone`
- `Edit`
- `Delete`
```ts
import {
AdaptableButton,
AdaptableOptions,
DashboardButtonContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Action Column Commands',
actionColumnOptions: {
actionColumns: [
{
columnId: 'action',
friendlyName: 'Actions',
actionColumnButton: [
{
command: 'clone',
},
{
command: 'edit',
},
{
command: 'delete',
},
],
},
],
},
rowFormOptions: {
autoHandle: true,
disableInlineEditing: true,
setPrimaryKeyValue: context => {
return {
...context.rowData,
id: context.adaptableApi.gridApi.getRowCount() + 1,
};
},
},
initialState: {
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'action',
'name',
'github_stars',
'update_stars',
'week_issue_change',
'update_issues',
'github_watchers',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Pinning Command Buttons
Action Columns, like all columns in AdapTable, can leverage standard [Column Pinning](https://www.adaptabletools.com/docs/handbook-layouts-table-pinning/index.md).
This will ensure that the Column containing the Command is always visible.
**Example: Action Column Commands Pinned**
Using Action Column Commands
- This demo provides 2 Action Columns which contain an `Edit` and `Delete` Action Command respectively
- The `Edit` Column is pinned to the left and the `Delete` Column is pinned to the right
- Because they are "normal" buttons we were able to add a label (of "Edit") to the first button
```ts
import {
AdaptableButton,
AdaptableOptions,
DashboardButtonContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Action Column Commands Pinned',
actionColumnOptions: {
actionColumns: [
{
columnId: 'edit',
friendlyName: ' ',
actionColumnButton: [
{
command: 'edit',
label: 'Edit',
},
],
},
{
columnId: 'delete',
friendlyName: ' ',
actionColumnButton: [
{
command: 'delete',
},
],
},
],
},
rowFormOptions: {
autoHandle: true,
disableInlineEditing: true,
setPrimaryKeyValue: context => {
return {
...context.rowData,
id: context.adaptableApi.gridApi.getRowCount() + 1,
};
},
},
initialState: {
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'edit',
'name',
'github_stars',
'update_stars',
'week_issue_change',
'update_issues',
'github_watchers',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'delete',
],
ColumnPinning: {
edit: 'left',
delete: 'right',
},
ColumnSizing: {
edit: {Width: 50},
delete: {Width: 50},
},
AutoSizeColumns: true,
},
],
},
},
};
```
## Configuring Command Buttons
Action Column Command Buttons can be configured in exactly the same way as 'normal' buttons.
They can be given a label, tone, variant or custom icon, and can be disabled or hidden.
The only difference is that if no icon is provided, AdapTable will use a default one
**Example: Configuring Action Column Commands**
Configuring Action Column Command Buttons
- This demo contains 3 Action Column Commands with some custom configuration:
- The `clone` button is **hidden** when the `Language` is 'JavaScript' (and has a custom icon)
- The `edit` button is **disabled** when the `Language` is 'HTML'
- The `delete` button **tone** is different when the `Language` is 'TypeScript'
```ts
import {
ActionColumnContext,
AdaptableButton,
AdaptableOptions,
DashboardButtonContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Action Column Commands',
actionColumnOptions: {
actionColumns: [
{
columnId: 'action',
friendlyName: 'Actions',
actionColumnButton: [
{
command: 'clone',
icon: {
// if this not provided then nothing shows in first row!!!
name: 'pie-chart',
},
hidden: (
button: AdaptableButton,
context: ActionColumnContext
) => {
return context.rowNode.data?.language == 'TypeScript';
},
},
{
command: 'edit',
disabled: (
button: AdaptableButton,
context: ActionColumnContext
) => {
return context.rowNode.data?.language == 'HTML';
},
},
{
command: 'delete',
buttonStyle: (
button: AdaptableButton,
context: ActionColumnContext
) => {
return {
variant: 'text',
tone:
context.rowNode.data?.language == 'JavaScript'
? 'info'
: 'error',
};
},
},
],
},
],
},
rowFormOptions: {
autoHandle: true,
disableInlineEditing: true,
setPrimaryKeyValue: context => {
return {
...context.rowData,
id: context.adaptableApi.gridApi.getRowCount() + 1,
};
},
},
initialState: {
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'action',
'name',
'github_stars',
'update_stars',
'week_issue_change',
'update_issues',
'github_watchers',
'license',
'language',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
],
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Configuring Action Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-action-column-configuring
- Action Columns are defined at Design Time
- Each Action Column Button can be configured to meet precise requirements
## Defining Action Columns
Action Columns are provided in the `actionColumns` property of [Action Column Options](https://www.adaptabletools.com/docs/handbook-action-column-technical-reference/index.md).
### `actionColumns`
Columns which contain an AdapTable Button - used for performing Actions
[`ActionColumn[]`](https://www.adaptabletools.com/docs/reference/actioncolumn.md)
This property is used for setting [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) in AdapTable.
The full definition of the [`ActionColumn`](https://www.adaptabletools.com/docs/reference/actioncolumn.md) object is as follows:
| Property | Type | Description |
| --- | --- | --- |
| [actionColumnButton](https://www.adaptabletools.com/docs/reference/actioncolumn.md#actioncolumnbutton) | [`ActionColumnButton`](https://www.adaptabletools.com/docs/reference/actioncolumnbutton.md)`<`[`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md)`> \| `[`ActionColumnButton`](https://www.adaptabletools.com/docs/reference/actioncolumnbutton.md)`<`[`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md)`>[]` | Button (or list of buttons) to display in the Column |
| [actionColumnSettings](https://www.adaptabletools.com/docs/reference/actioncolumn.md#actioncolumnsettings) | [`ActionColumnSettings`](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md) | Optional properties to configure the Column (e.g. filterable, resizable) |
| [columnId](https://www.adaptabletools.com/docs/reference/actioncolumn.md#columnid) | `string` | Mandatory 'Id'; if no value set for `FriendlyName`, this will also be Column name |
| [friendlyName](https://www.adaptabletools.com/docs/reference/actioncolumn.md#friendlyname) | `string` | How Column appears in Column Header, Menus; if no value set, `ColumnId` is used |
| [rowScope](https://www.adaptabletools.com/docs/reference/actioncolumn.md#rowscope) | [`RowScope`](https://www.adaptabletools.com/docs/reference/rowscope.md) | Which types of Rows should contain buttons (i.e. data, grouped, summary) |
Developers define 3 main sets of information when providing an Action Column Definition:
### Identifiers
Each Action Column has 2 forms of identification:
- `Id` - used internally when referencing the Column in other Objects like Layouts
- `FriendlyName` - used in the UI, e.g. in Wizards
### Button
The button(s) is at the heart of the Action Column.
It is an [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) which means that it can be styled and configured to user requirements.
### The Action Column Button
The `actionColumnButton` gives developers complete control over button visibility, rendering and behaviour.
Many of these properties are JavaScript functions which receive a `Context` property.
For Action Buttons this takes the form of an [`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md) which is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [actionColumn](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md#actioncolumn) | [`ActionColumn`](https://www.adaptabletools.com/docs/reference/actioncolumn.md)`` | Action Column in question |
| [data](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md#data) | `TData` | The current row's data |
| [primaryKeyValue](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md#primarykeyvalue) | `any` | Primary Key Value in current row |
| [rowNode](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md#rownode) | `IRowNode` | Current AG Grid Row Node |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
### Settings
The behaviour of each Action Column can be configured also. e.g. width, movable, resizable etc.
### Action Column Settings
The `actionColumnSettings` property is of type [`ActionColumnSettings`](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md) which has these properties:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [autoWidth](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#autowidth) | `boolean` | When true, estimates column width from button labels/icons (or dropdown label) at setup time. Dynamic labels and icons (functions) are not measured — set `width` explicitly in those cases. | false |
| [displayMode](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#displaymode) | `ActionColumnDisplayMode` | How buttons are rendered in the column. In `'dropdown'` mode, per-button `buttonStyle` and `iconPosition` are ignored; the trigger uses fixed styling and menu items use the standard list layout (icon, then label). | 'buttons' |
| [dropdownLabel](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#dropdownlabel) | `string` | Label on the dropdown trigger when `displayMode` is `'dropdown'` | 'Actions' |
| [minWidth](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#minwidth) | `number` | Minimum width (in pixels) for the column; also used as the column width when `autoWidth` is false | |
| [resizable](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#resizable) | `boolean` | Whether Column can be resized (by dragging column header edges) | true |
| [suppressMenu](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#suppressmenu) | `boolean` | Whether no menu should be shown for this Column header. | false |
| [suppressMovable](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#suppressmovable) | `boolean` | Whether if this Column should be movable via dragging | false |
| [width](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#width) | `number` | Preferred width (in pixels) for Column; takes precedence over `autoWidth` and `minWidth` | |
### Putting it Together
### Defining an Action Column
There are a number of stages to defining an Action Column.
This example is taken from the `Update Stars` Action Column - in the demo on the previous page.
The Action Column displays a button that will either Add or Remove a Star based on various parameters.
In this example the Action Column contains one button - but there is no limit on the number that can be displayed
Supply 2 string properties:
- `columnId` - how the Column is referred to in Code
- `friendlyName` - the caption for the Column (if not provided the `columnId` value is used)
Use the [`ActionColumnSettings`](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md) property to set key Column properties including:
- Column Width
- Resizable
- Movable
- Column Menu visibility
In this example we don't show the Column Menu and prevent the column from being moved or resized.
The label for the Action Button is a string value that can be:
- a hard-coded value
- returned from a function (which receives Context)
In this example we provide a function which returns either 'Add Star' or 'Remove Star' depending on other row values
The Action Button style is of type [`ButtonStyle`](https://www.adaptabletools.com/docs/reference/buttonstyle.md) that can be:
- a hard-coded value
- returned from a function (which receives Context)
In this example we provide a function which returns 2 different styles depending on other row values
`onClick` is the function that is invoked when the Action Button is clicked.
In this example it increments or decrements a cell based on the arguments supplied.
Use the 2 boolean `hidden` and `disabled` properties to specify whether button is visible and enabled.
Each property can return:
- a hard-coded value
- returned from a function (which receives Context)
In this example we hide and disable the Button in some rows based on the function evaluation.
hello ```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "5M"],[5, 2, "WHERE [Currency] = 'USD' AND [RequiredDate] < ADD_DAYS(CURRENT_DAY, 30)"]]
```ts [[1, 7, "columnId"], [1, 8, "friendlyName"], [2, 9, "actionColumnSettings"], [3, 15, "label"], [4, 24, "buttonStyle"], [5, 39, "onClick"], [6, 54, "hidden"], [6, 64, "disabled"]]
// Provide an Update Stars Action Button
// For rows where the language is JavaScript it will:
// Add Star to Stars Column (and display a different style)
// otherwise it will Remove a Star
// We also provide rules whether Button is Visible or Enabled
{
columnId: 'update_issues',
friendlyName: 'Update Stars',
actionColumnSettings:{
suppressMenu: true,
suppressMovable: true,
resizable: false
},
actionColumnButton: {
label: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
return rowData.language === 'JavaScript'
? 'Add Star'
: 'Remove Star';
},
buttonStyle: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
return rowData.language === 'JavaScript'
? {
variant: 'raised',
tone: 'accent',
}
: {
variant: 'raised',
tone: 'success',
};
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
let increment =
rowData.language === 'JavaScript' ? 1 : -1;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: rowData.github_stars + increment,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
hidden: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
return (
rowData.name === 'stencil' ||
rowData.name === 'polymer'
);
},
disabled: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
return rowData.github_watchers < 200;
},
},
},
```
## AG Grid Column Definitions
In most cases Action Columns are **not** provided in the `ColDefs` property in AG Grid GridOptions.
Instead the Action Columns provided in Action Column Options suffice for AdapTable to be able to create the associated AG Grid column automatically.
However sometimes a developer might want to add an AG Grid element to the Action Column.
For instance a tooltip might be needed, or there might be a requirement to put the Action Column inside a Column Group (which is an AG Grid feature).
This is possible: a column can be provided in AG Grid ColDefs but by specifying a of `actionColumn`, AdapTable will automatically wire it up with an associated Action Column definition.
- Set the to be `actionColumn`
- Make sure `ColId` in the AG Grid ColDef and `ColumnId` in the Action Column definition are the same value
See for more details and a demo
Action Columns: Adding AG Grid properties
- This demo contains an AG Grid Column Group - `Actions`
- The group contains 2 Action Columns for adding and deleting issues
- Both the Column Group and the 2 containing Columns were defined in AG Grid Column Defs
- The 2 columns in the Group were given AG Grid Header and Cell ToolTips
- They were also given a type of `actionColumn` which is what allowed AdapTable to wire everything together
The column group and containing columns are defined in AG Grid:
```js
{
headerName: 'Actions',
children: [
{
colId: 'add_issue',
cellDataType: 'number'
type: ['actionColumn'],
headerTooltip: 'Add an issue',
tooltipValueGetter: (params: ITooltipParams) => {
return 'Add 1 to ' + params.data.week_issue_change;
},
},
{
colId: 'delete_issue',
type: ['actionColumn'],
headerTooltip: 'Delete an Issue',
tooltipValueGetter: (params: ITooltipParams) => {
return 'Delete 1 from ' + params.data.week_issue_change;
},
},
],
},
```
and referenced in Action Column Options:
```ts
actionColumnOptions: {
actionColumns: [
{
columnId: 'add_issue',
friendlyName: 'Add Issue',
actionColumnButton: [
{
label: 'Up',
buttonStyle: {
variant: 'outlined',
tone: 'info',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'week_issue_change',
newValue: rowData.week_issue_change + 1,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest
);
},
},
],
},
{
columnId: 'delete_issue',
friendlyName: 'Delete Issue',
actionColumnButton: [
{
label: 'Down',
buttonStyle: {
variant: 'outlined',
tone: 'warning',
},
onClick: (
button: ActionColumnButton,
context: ActionColumnContext
) => {
let rowData: any = context.rowNode?.data;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'week_issue_change',
newValue: rowData.week_issue_change - 1,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
},
],
},
],
},
```
- Hover over a Button in an Action Column and see the Tooltip which AG Grid provides
```ts file=aggrid-action-columns-demo/adaptableOptions.ts
```
```ts file=aggrid-action-columns-demo/columnDefs.ts
```
## Grouped & Summary Rows
By default Action Columns will appear in **every** row in AG Grid.
If this behaviour is unwanted, the property can be used to 3 types of Rows (all visible by default):
- Grouped Rows
- Summary Rows
- Data Rows
- The Action Column contains a object, which has a `hidden` property
- This enables a much more granular approach, i.e. to hide an Action Column button on a row-by-row basis
Displaying Action Columns in Grouped and Summary Rows
- In this example we define an Action Column with the `rowScope` property set to exclude Grouped Rows and Summary Rows
- Accordingly we only see the `Add Star` Action Column in actual Data Rows
The Action Column definition includes the rowScope property:
```ts
rowScope: {
ExcludeGroupRows: true,
ExcludeSummaryRows: true,
},
```
```ts file=action-column-grouping-demo/adaptableOptions.ts
```
---
# Action Columns Technical Reference
Canonical page: https://www.adaptabletools.com/docs/handbook-action-column-technical-reference
- Action Column Options is used to define [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md)
- The Action Column API provides run-time access to Action Columns
-----------
## Action Column Options
The [`Action Column Options`](https://www.adaptabletools.com/docs/reference/actioncolumnoptions.md) section of [Adaptable Options](https://www.adaptabletools.com/docs/technical-reference-adaptable-options/index.md) is used to configure Action Columns.
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [actionColumns](https://www.adaptabletools.com/docs/reference/actioncolumnoptions.md#actioncolumns) | [`ActionColumn`](https://www.adaptabletools.com/docs/reference/actioncolumn.md)`[]` | Columns which contain an AdapTable Button - used for performing Actions | undefined |
### Action Column
| Property | Type | Description |
| --- | --- | --- |
| [actionColumnButton](https://www.adaptabletools.com/docs/reference/actioncolumn.md#actioncolumnbutton) | [`ActionColumnButton`](https://www.adaptabletools.com/docs/reference/actioncolumnbutton.md)`<`[`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md)`> \| `[`ActionColumnButton`](https://www.adaptabletools.com/docs/reference/actioncolumnbutton.md)`<`[`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md)`>[]` | Button (or list of buttons) to display in the Column |
| [actionColumnSettings](https://www.adaptabletools.com/docs/reference/actioncolumn.md#actioncolumnsettings) | [`ActionColumnSettings`](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md) | Optional properties to configure the Column (e.g. filterable, resizable) |
| [columnId](https://www.adaptabletools.com/docs/reference/actioncolumn.md#columnid) | `string` | Mandatory 'Id'; if no value set for `FriendlyName`, this will also be Column name |
| [friendlyName](https://www.adaptabletools.com/docs/reference/actioncolumn.md#friendlyname) | `string` | How Column appears in Column Header, Menus; if no value set, `ColumnId` is used |
| [rowScope](https://www.adaptabletools.com/docs/reference/actioncolumn.md#rowscope) | [`RowScope`](https://www.adaptabletools.com/docs/reference/rowscope.md) | Which types of Rows should contain buttons (i.e. data, grouped, summary) |
### Action Column Settings
The [`Action Column Settings`](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md) object provides configuration properties:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [autoWidth](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#autowidth) | `boolean` | When true, estimates column width from button labels/icons (or dropdown label) at setup time. Dynamic labels and icons (functions) are not measured — set `width` explicitly in those cases. | false |
| [displayMode](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#displaymode) | `ActionColumnDisplayMode` | How buttons are rendered in the column. In `'dropdown'` mode, per-button `buttonStyle` and `iconPosition` are ignored; the trigger uses fixed styling and menu items use the standard list layout (icon, then label). | 'buttons' |
| [dropdownLabel](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#dropdownlabel) | `string` | Label on the dropdown trigger when `displayMode` is `'dropdown'` | 'Actions' |
| [minWidth](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#minwidth) | `number` | Minimum width (in pixels) for the column; also used as the column width when `autoWidth` is false | |
| [resizable](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#resizable) | `boolean` | Whether Column can be resized (by dragging column header edges) | true |
| [suppressMenu](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#suppressmenu) | `boolean` | Whether no menu should be shown for this Column header. | false |
| [suppressMovable](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#suppressmovable) | `boolean` | Whether if this Column should be movable via dragging | false |
| [width](https://www.adaptabletools.com/docs/reference/actioncolumnsettings.md#width) | `number` | Preferred width (in pixels) for Column; takes precedence over `autoWidth` and `minWidth` | |
### Action Column Button
The button in the Action extends the [`Adaptable Button`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md) defined as follows:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [buttonStyle](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#buttonstyle) | [`ButtonStyle`](https://www.adaptabletools.com/docs/reference/buttonstyle.md)` \| ((button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => `[`ButtonStyle`](https://www.adaptabletools.com/docs/reference/buttonstyle.md)`)` | Style for Button - can be object or function that provides a `ButtonStyle` object | |
| [disabled](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#disabled) | `(button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => boolean` | Function that disables / enables the button based on its evaluation result | |
| [hidden](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#hidden) | `(button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => boolean` | Function which sets whether Button is hidden | |
| [icon](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#icon) | [`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)` \| ((button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => `[`AdaptableIcon`](https://www.adaptabletools.com/docs/reference/adaptableicon.md)`)` | Icon for Button - can be object or function that provides a `AdaptableIcon` object | |
| [iconPosition](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#iconposition) | `'start' \| 'end'` | Where the icon appears relative to the label | 'start' |
| [label](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#label) | `string \| ((button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => string)` | Label for Button - can be string or function that provides string | |
| [onClick](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#onclick) | `(button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => void` | Function to invoke when button is clicked | |
| [tooltip](https://www.adaptabletools.com/docs/reference/adaptablebutton.md#tooltip) | `string \| ((button: `[`AdaptableButton`](https://www.adaptabletools.com/docs/reference/adaptablebutton.md)`, context: CONTEXT_TYPE) => string)` | Tooltip for Button - can be string or function that provides string | |
But it also contains a `command` property useful for [wiring up Action Column Commands](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md)
| Property | Type | Description |
| --- | --- | --- |
| [command](https://www.adaptabletools.com/docs/reference/actioncolumnbutton.md#command) | [`ActionButtonCommand`](https://www.adaptabletools.com/docs/reference/actionbuttoncommand.md) | Command to assign to Action Column Button that displays a Row Form |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/actioncolumnbutton.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
-----------
## Action Column API
The [`Action Column API`](https://www.adaptabletools.com/docs/reference/actioncolumnapi.md) section of [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) provides programmatic access to Action Columns:
| Method | Returns | Description |
| --- | --- | --- |
| [getActionColumnForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/actioncolumnapi.md#getactioncolumnforcolumnid) | [`ActionColumn`](https://www.adaptabletools.com/docs/reference/actioncolumn.md)` \| undefined` | Returns Action Column with given Id |
| [getActionColumns()](https://www.adaptabletools.com/docs/reference/actioncolumnapi.md#getactioncolumns) | [`ActionColumn`](https://www.adaptabletools.com/docs/reference/actioncolumn.md)`[]` | Retrieves the Action Columns provided in Action Column Options |
---
# Displaying Column Aggregations
Canonical page: https://www.adaptabletools.com/docs/handbook-aggregation
- Aggregations are supported via Layouts
- AdapTable provides a special Aggregation for Weighted Averages
AG Grid's [Aggregation functionality](https://www.ag-grid.com/javascript-data-grid/aggregation/) displays aggregations of column values.
- Aggregations are displayed by AG Grid in used when [Grouped Rows](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md)
- By default, Aggregations display `sum` of values, but many different aggregation types are available
AdapTable [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) provide full support in for AG Grid Aggregations, including:
- Ability to **define** ָAggregations in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md) - for both [Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md) and [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md)
- Automatic **Persistence** of Aggregations created at run-time into Layout section of [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md), and then be dynamically re-applied when the Layout next loads
- Two **custom** Aggregations for [Weighted Averages](https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average/index.md) and [Only](https://www.adaptabletools.com/docs/handbook-aggregation-only/index.md)
- Support for [Grand Total Rows](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md) which display the totals for all cells in the Grid (and not a single Group)
- AdapTable additionally provides a very useful and powerful [Row Summary](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md) feature
- This allows users to see aggregation information even **when there is no Row Grouping**
## Aggregations in Column Header
By default AG Grid prefixes the type of the aggregation function (aka `aggFunc`) to the Column's header.
For instance adding `sum` to a `Price` column will result in a Column header of "(sum) Price".
AdapTable allows this to be overridden through the `SuppressAggFuncInHeader` property in each [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md).
This override is **per Layout** in AdapTable and not applied globally
- There is an AG Grid GridOptions property called `suppressAggFuncInHeader` which does the same thing
- The Layout's `SuppressAggFuncInHeader` property **replaces** this and is only place where this functionality can be set
**Example: Aggregations: Column Headers**
Hiding the aggFunc from the Column Header
- This example includes 2 Layouts - one Table (with [Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md)) and one Pivot - each with 2 `sum` Aggregations - on `Github Watchers` & `Github Stars` Columns
- We have set `SuppressAggFuncInHeader` to *true* so that in both Layouts you see just "Github Stars" instead of "(sum) Github Stars".
- Click the Custom Toolbar to show / hide AggFuncs in the Column Header (the buttons invoke the [updateCurrentLayout](https://www.adaptabletools.com/docs/handbook-layouts-updating/index.md) function in [Layout API](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md))
```ts
import {
AdaptableButton,
AdaptableOptions,
ApplicationDataEntry,
CustomToolbarButtonContext,
DashboardButtonContext,
Layout,
} from '@adaptabletools/adaptable';
import {tr} from 'date-fns/locale';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Suppressing Agg Funcs in Header',
dashboardOptions: {
customToolbars: [
{
name: 'custombuttons',
toolbarButtons: [
{
label: 'Show Agg Funcs',
buttonStyle: {
tone: 'neutral',
variant: 'outlined',
},
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.layoutApi.updateCurrentLayout(
(layout: Layout) => {
layout.SuppressAggFuncInHeader = false;
return layout;
}
);
},
},
{
label: 'Hide Agg Funcs',
buttonStyle: {
tone: 'neutral',
variant: 'outlined',
},
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
context.adaptableApi.layoutApi.updateCurrentLayout(
(layout: Layout) => {
layout.SuppressAggFuncInHeader = true;
return layout;
}
);
},
},
],
},
],
},
initialState: {
Dashboard: {
PinnedToolbars: ['custombuttons', 'Layout'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Grouped Table Layout',
Layouts: [
{
Name: 'Grouped Table Layout',
RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
],
SuppressAggFuncInHeader: true,
TableColumns: [
'name',
'github_stars',
'language',
'github_watchers',
'updated_at',
'license',
'created_at',
],
},
{
Name: 'Pivot Layout',
PivotColumns: ['language'],
PivotGroupedColumns: ['license'],
SuppressAggFuncInHeader: true,
PivotAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
],
},
],
},
},
};
```
## Formatting & Styling Aggregations
AdapTable allows users to [format and style](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) AggFuncs in a grouped row, in exactly the same way as a data row.
See [Formatting and Styling Aggregations](https://www.adaptabletools.com/docs/handbook-aggregation-formatting/index.md) for more information and demos
## Defining Aggregations
### Defining a Layout with Aggregations
A Table Layout can define which Aggregations are available in **Grouped Rows**, using the `TableAggregationColumns` property.
The [`TableAggregationColumns`](https://www.adaptabletools.com/docs/reference/tableaggregationcolumns.md) object contains 2 items:
- a `ColumnId` (string)
- either an `aggFunc` (e.g. sum) or *true* (uses default `aggFunc`)
You can supply [Weighted Average Aggregations](https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average/index.md) if needed.
In this case 2 properties must be provided to the definition:
- `type` - always set to 'weightedAverage'
- `weightedColumnId` - column which provides the Weight
Set `GrandTotalRow` prop to display a [Row providing Totals of all aggregations](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md).
Options for the property are:
- `top` - shows it at top of grid
- `bottom` - shows it at bottom of grid
- `true` - equivalent to `top`
- `false` - doesn't display it
Setting `SuppressAggFuncInHeader` to *true* hides the name of the aggFunc in the Column Header, e.g. it will show 'Open PRs' instead of 'sum(Open PRs)'
```ts [[1, 14, "TableAggregationColumns"], [2, 30, "weightedAverage"], [3, 34, "GrandTotalRow"], [4, 35, "SuppressAggFuncInHeader"]]
// Define a Layout with 3 Aggregations:
// open_pr_count (avg), github_watchers (sum) & github_stars (default aggFunc for col)
// Weighted Aggregation for examResult (using attendance as Weighted Column)
// Provide a GrandTotalRow at top of Grid
// Set Aggregation Columns to display without name of the aggFunc
const initialState: InitialState = {
Layout: {
CurrentLayout: 'Grouping Layout',
Layouts: [
{
Name: 'Grouping Layout',
TableColumns: ['github_stars', 'open_pr_count', 'github_watchers', 'examResult', 'attendance'],
RowGroupedColumns: ['license', 'language'],
TableAggregationColumns: [
{
ColumnId: 'open_pr_count',
AggFunc: 'avg'
},
{
ColumnId: 'github_watchers',
AggFunc: 'sum'
},
{
ColumnId: 'github_stars',
AggFunc: true
},
{
ColumnId: 'examResult',
AggFunc: {
type: 'weightedAverage',
weightedColumnId: 'attendance',
},
}],
GrandTotalRow: 'top',
SuppressAggFuncInHeader: true,
}],
},
}
```
---
# Formatting Aggregations
Canonical page: https://www.adaptabletools.com/docs/handbook-aggregation-formatting
- Aggregated Cells can be formatted and styled (including by using Conditions)
- It is possible to configure the formatting so that only the grouped (and not data) rows are formatted
AdapTable allows users to [format and style](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) aggregated cells in a grouped row.
It is also possible to format Grand Total Rows - see [Grand Total Rows: Formatting](https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row/index.md#formatting) for more information
This is done in exactly the same way as a data row, meaning it is also possible to create [Conditional Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md).
- It is possible to set formatting so that **only** the aggregated values are formatted
- This is done by setting the `RowScope` property to `ExcludeDataRows` in the Format Definition (or Format Wizard)
**Example: Aggregations: Formatting**
Formatting and Styling Aggregations
- In this example we have provided a [Format Column](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) of light blue and bold to the `Github Stars` and `Github Watchers` Columns with 2 features:
- We set it only to display in Grouped Rows (by excluding Data Rows)
- We added a condition of >3000 (which is why `Github Watchers` in _HTML_ row doesnt display the style)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Formatting Agg Funcs',
initialState: {
Dashboard: {
Tabs: [{Name: 'Demo', Toolbars: ['Layout']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github_stars',
Scope: {ColumnIds: ['github_stars', 'github_watchers']},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [3000],
},
],
},
Style: {
ForeColor: 'Pink',
FontWeight: 'Bold',
},
RowScope: {
ExcludeDataRows: true,
},
},
],
},
Layout: {
CurrentLayout: 'Grouped Layout',
Layouts: [
{
Name: 'Grouped Layout',
RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
],
TableColumns: [
'name',
'github_stars',
'language',
'github_watchers',
'updated_at',
'license',
'created_at',
],
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Grand Total Rows
Canonical page: https://www.adaptabletools.com/docs/handbook-aggregation-grand-total-row
- AdapTable Layouts can include a Grand Total Row which displays aggregated information
[Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md) can include a Grand Total Row which will display the totals for all Aggregated Cells.
- Grand Total Rows use whichever `aggFunc` is being applied in the Column being aggregated
- Unlike "normal" aggregations, Grand Total Rows display even if [Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) is not applied
This is done via the `GrandTotalRow` property which can be set to one of 6 values:
| Property Value | Behaviour |
| -------------- | ------------------------------------------------- |
| `top` | Grand Total Row is displayed at top of grid |
| `bottom` | Grand Total Row is displayed at bottom of grid |
| `pinnedTop` | Grand Total Row is pinned to the top of grid |
| `pinnedBottom` | Grand Total Row is pinned to the bottom of grid |
| `true` | Equivalent to `pinnedTop` |
| `false` | Grand Total Row is not displayed (same as `null`) |
- The `GrandTotalRow` property is in the [`LayoutBase`](https://www.adaptabletools.com/docs/reference/layoutbase.md) object, and therefore available in both [Table](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md) and [Pivot](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) Layouts
- [Row Summaries](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md) are a more powerful and configurable alternative (but available only in Table Layouts)
**Example: Aggregations: Grand Total Row**
Providing a Row showing Total of all Aggregations
- This demo provides 3 Layouts all of which have 3 Aggregated Columns - `Github Stars` (sum), `Github Watchers` (sum) and `Issue Change` (min) - and a Grand Total Row
- `Grouped Layout` - the Grid is Row Grouped and the Grand Total Row is at the top
- `Pivot Layout` - the Grid is Pivoted and the Grand Total Row is at the bottom
- `Standard Layout` - the Grid has now Row Groups and the Grand Total Row is pinned to the top
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Aggregation Grand Total Row',
initialState: {
Dashboard: {
Tabs: [{Name: 'Demo', Toolbars: ['Layout']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Grouped Layout',
Layouts: [
{
Name: 'Standard Layout',
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'week_issue_change',
AggFunc: 'min',
},
],
SuppressAggFuncInHeader: true,
GrandTotalRow: 'pinnedTop',
TableColumns: [
'name',
'github_watchers',
'github_stars',
'week_issue_change',
'updated_at',
'license',
'created_at',
],
},
{
Name: 'Grouped Layout',
RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'week_issue_change',
AggFunc: 'min',
},
],
SuppressAggFuncInHeader: true,
GrandTotalRow: 'top',
TableColumns: [
'name',
'github_watchers',
'github_stars',
'week_issue_change',
'updated_at',
'license',
'created_at',
],
},
{
Name: 'Pivot Layout',
PivotColumns: [],
PivotGroupedColumns: ['language'],
SuppressAggFuncInHeader: true,
PivotAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'week_issue_change',
AggFunc: 'min',
},
],
GrandTotalRow: 'bottom',
},
],
},
},
};
```
## Formatting
By default, Grand Total Rows will be included in all [Column Formatting and Styling](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md).
This behaviour can be changed by configuring the `RowScope` property when defining the Format Column.
The [`RowScope`](https://www.adaptabletools.com/docs/reference/rowscope.md) object enables 4 types of rows to be **excluded** from the Format Column:
- Data Rows
- Grouped Rows
- Summary Rows
- Grand Total Rows - the focus of this page
Use the `ExcludeDataRows` option to create a Format Column that is **only** rendered in a Grand Total Row
**Example: Aggregations: Grand Total Row Formatting**
Formatting Grand Total Rows
- This demo contains a Grand Total Row with 3 Aggregated Columns, and 3 Format Columns each with a different `RowScope`:
- `Github Watchers` **includes** Grand Total Row but **excludes** Data Rows
- `Github Stars` **excludes** Grand Total Row but **includes** Data Rows
- `Issue Change` **includes both** Grand Total Row and Data Rows
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Aggregation Grand Total Row Formatting',
initialState: {
Dashboard: {
Tabs: [{Name: 'Demo', Toolbars: ['Layout']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Table Layout',
Layouts: [
{
Name: 'Table Layout',
// RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'week_issue_change',
AggFunc: 'sum',
},
],
SuppressAggFuncInHeader: true,
GrandTotalRow: 'top',
TableColumns: [
'name',
'github_watchers',
'github_stars',
'week_issue_change',
'updated_at',
'license',
'created_at',
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github_watchers',
Scope: {
ColumnIds: ['github_watchers'],
},
Style: {
ForeColor: 'LightBlue',
FontWeight: 'Bold',
Alignment: 'Center',
},
RowScope: {
ExcludeDataRows: true,
},
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
Style: {
ForeColor: 'LightGreen',
FontWeight: 'Bold',
},
RowScope: {
ExcludeTotalRows: true,
},
},
{
Name: 'formatColumn-week_issue_change',
Scope: {
ColumnIds: ['week_issue_change'],
},
Style: {
ForeColor: 'Red',
FontWeight: 'Bold',
Alignment: 'Center',
},
},
],
},
},
};
```
---
# Aggregation Function - only
Canonical page: https://www.adaptabletools.com/docs/handbook-aggregation-only
- The 'only' aggregation is provided by AdapTable to supplement the Aggregation Functions provided by AG Grid
- It returns a value if that value is the only one that appears in the aggregated data group
AdapTable provides an `only` aggregation function for use in [Grouped Layouts](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md).
This is separate from, and in addition to, the `ONLY` aggregation function in [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md), used in [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md)
The `only` aggregation returns a value **if that value is the only one** that appears in the aggregated data group.
A set of [5, 5, 4] will return null, as will a set of [5, 5, null] - but a set of [5, 5, 5] will return 5
**Example: Aggregations: 'Only' Custom Aggregation**
Using the Only Aggregation
- In this example we group on the `Language` Column and provide 2 **only** aggregations - on the `License` and `Issue Change` Columns
- We have also amended the usual row Data so that all the values for `HTML` in the `License` column are "MIT License", and all the `TypeScript` values in the `Issues Change Column` are "12"
- As a result we see the `only` aggregation return these values for these 2 groups
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Only Aggregation',
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Grouped Layout',
Layouts: [
{
Name: 'Grouped Layout',
RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'week_issue_change',
AggFunc: 'only',
},
{
ColumnId: 'license',
AggFunc: 'only',
},
],
RowGroupValues: {
RowGroupDefaultBehavior: 'always-expanded',
},
TableColumns: [
'name',
'github_watchers',
'license',
'week_issue_change',
'github_stars',
'updated_at',
'created_at',
'language',
],
ColumnSorts: [
{
ColumnId: 'language',
SortOrder: 'Asc',
},
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-license-issue-change',
Scope: {
ColumnIds: ['license', 'week_issue_change'],
},
Style: {
FontStyle: 'Italic',
ForeColor: 'LightGreen',
FontWeight: 'Bold',
},
RowScope: {
ExcludeDataRows: true,
},
},
],
},
CustomSort: {
CustomSorts: [
{
Name: 'customSort-language',
ColumnId: 'language',
SortedValues: ['HTML', 'TypeScript', 'JavaScript'],
},
],
},
},
};
```
```ts
export interface WebFramework {
id: number;
name: string;
full_name?: string;
html_url?: string;
description: string;
created_at: string;
updated_at: string;
pushed_at: string;
homepage?: string;
github_stars: number;
language: string;
forks_count?: number;
open_issues_count: number;
license: string;
topics?: string[];
github_watchers: number;
has_projects: boolean;
has_wiki: boolean;
has_pages: boolean;
closed_issues_count: number;
open_pr_count: number;
closed_pr_count: number;
week_issue_change: number;
}
export const rowData: WebFramework[] = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 179429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78348,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 191435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 53935,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'Other',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 12,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 19338,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 9752,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 11049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: 12,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'HTML',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 13064,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'MIT License',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 27840,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 10122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: new Date('2021-12-20T09:02:15').toDateString(),
pushed_at: new Date('2021-12-17T23:21:58').toDateString(),
homepage: 'https://preactjs.com',
github_stars: 30538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date('2021-12-17T20:09:25').toDateString(),
homepage: 'https://riot.js.org',
github_stars: 14597,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date('2021-12-20T08:21:58').toDateString(),
homepage: 'https://nextjs.org',
github_stars: 78446,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date('2021-12-20T08:05:15').toDateString(),
homepage: 'https://nuxtjs.org',
github_stars: 38997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 20095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
## Hiding Only Aggregation
It is possible to hide the `only` aggregation if this is not required or useful to your users.
This is done the same way as hiding AG Grid's aggFuncs - via the `allowedAggFuncs` in each ColumnDef.
Hide the `only` aggFunc by omitting it from list of Column's aggFuncs, e.g. `allowedAggFuncs: ['sum', 'min', 'max'],`
**Example: Aggregations: 'Only' Custom Aggregation (Hiding)**
Hiding the Only Aggregation
- In this example we have removed the `only` aggFunc from the list of available aggFuncs for the `Github Stars` and `Github Watchers` columns
- We have explicitly provided it for the Week Issue Change column (together with `sum`)
- We have not provided any `allowedAggFuncs` for the `License` column (meaning that only is automatically available together with all AG Grid aggFuncs)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Hiding Only Aggregation',
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Grouped Layout',
Layouts: [
{
Name: 'Grouped Layout',
RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'week_issue_change',
AggFunc: 'only',
},
{
ColumnId: 'license',
AggFunc: 'only',
},
],
RowGroupValues: {
RowGroupDefaultBehavior: 'always-expanded',
},
TableColumns: [
'name',
'github_watchers',
'license',
'week_issue_change',
'github_stars',
'updated_at',
'created_at',
'language',
],
ColumnSorts: [
{
ColumnId: 'language',
SortOrder: 'Asc',
},
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-license-issue-change',
Scope: {
ColumnIds: ['license', 'week_issue_change'],
},
Style: {
FontStyle: 'Italic',
ForeColor: 'LightGreen',
FontWeight: 'Bold',
},
RowScope: {
ExcludeDataRows: true,
},
},
],
},
CustomSort: {
CustomSorts: [
{
Name: 'customSort-language',
ColumnId: 'language',
SortedValues: ['HTML', 'TypeScript', 'JavaScript'],
},
],
},
},
};
```
```ts
export interface WebFramework {
id: number;
name: string;
full_name?: string;
html_url?: string;
description: string;
created_at: string;
updated_at: string;
pushed_at: string;
homepage?: string;
github_stars: number;
language: string;
forks_count?: number;
open_issues_count: number;
license: string;
topics?: string[];
github_watchers: number;
has_projects: boolean;
has_wiki: boolean;
has_pages: boolean;
closed_issues_count: number;
open_pr_count: number;
closed_pr_count: number;
week_issue_change: number;
}
export const rowData: WebFramework[] = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 179429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78348,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 191435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 53935,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'Other',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 12,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 19338,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 9752,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 11049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: 12,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'HTML',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 13064,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'MIT License',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 27840,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 10122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: new Date('2021-12-20T09:02:15').toDateString(),
pushed_at: new Date('2021-12-17T23:21:58').toDateString(),
homepage: 'https://preactjs.com',
github_stars: 30538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date('2021-12-17T20:09:25').toDateString(),
homepage: 'https://riot.js.org',
github_stars: 14597,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date('2021-12-20T08:21:58').toDateString(),
homepage: 'https://nextjs.org',
github_stars: 78446,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date('2021-12-20T08:05:15').toDateString(),
homepage: 'https://nuxtjs.org',
github_stars: 38997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 20095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
{
field: 'name',
cellDataType: 'text',
sortable: true,
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
allowedAggFuncs: ['sum', 'min', 'max'],
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
editable: false,
allowedAggFuncs: ['sum', 'min', 'max'],
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
allowedAggFuncs: ['sum', 'only'],
},
{
field: 'license',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{
field: 'has_wiki',
headerName: 'Has Wiki',
cellDataType: 'boolean',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
];
```
---
# Using Weighted Averages
Canonical page: https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average
- AdapTable offers 2 ways to provide Weighted Averages:
- through Weighted Average Aggregations in a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) (referencing the Weighted Column)
- via the `AVG` [AdapTableQL Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) which takes an optional `WEIGHT` parameter
- Additionally Weighted Average aggregations can be viewed in [Cell Summary Operations](https://www.adaptabletools.com/docs/handbook-summarising/index.md)
Weighted Averages are a specialised form of aggregation.
They provide a more 'accurate' average of a data set than simply using the arithmetic mean.
As defined by [Investopedia](https://www.investopedia.com/terms/w/weightedaverage.asp):
Weighted average is a calculation that takes into account the varying degrees of importance of the numbers in a data set. In calculating a weighted average, each number in the data set is multiplied by a predetermined weight before the final calculation is made.
- Weighted Averages are commonly used in finance e.g. for statistical analysis or stock portfolios
- But they can be used elsewhwere, for example for teacher grading averages
AdapTable provides 3 different ways of viewing Weighted Averages:
- Creating a Weighted Average **Aggregation** in a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md)
- Seeing the Weighted Average **Summary** in the [Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising/index.md) or [Row Summary](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md)
- Providing a Weighted Average **Calculation** in an [AdapTableQL Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)
## Weighted Average Aggregations
In AdapTable Columns can be defined as having Weighted Average Aggregations.
These definitions can be provided by both developers at design-time and end users at run-time.
Each [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) in AdapTable contains a `TableAggregationColumns` (or `PivotAggregationColumns`) property.
This defines which Columns to aggregate, and which operation to use, when the Grid is Row-Grouped.
Guides for Defining [Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md) and [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) explain in detail how to provide Aggregations
The `TableAggregationColumns` (or `PivotAggregationColumns`) property can also be of type *WeightedAverageAggregation*.
Adaptable provides a custom aggFunc of `weightedAverage` which is added to the aggFuncs supplied by AG Grid
This object is a record where the key is the name of the Column which will be Aggregated, and a `weightedColumnId` property supplies the name of the column providing the Weight.
There is also a `type` property which should always be set to 'weightedAverage'
So imagine a scenario where you have a Grid with an `examResult` column but you want to provide a weighted average using another column, `attendance` in the calculation.
The Initial Adaptable State to create the Weighted Average would be:
```ts
TableAggregationColumns: [
{
ColumnId: 'examResult',
AggFunc: {
type: 'weightedAverage',
weightedColumnId: 'attendance',
},
},
],
```
- It is also possible to create a Weighted Average aggregation using the [Table Layout Wizard](https://www.adaptabletools.com/docs/handbook-layouts-wizard-table/index.md)
- When `weightedAvg` is the selected *aggFunc*, AdapTable will display a second dropdown for the Weighted Column
### Column Menu
AdapTable also allows you to set the Weighted Average aggregation from the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md).
The menu item only appears when the grid is **row grouped** (same as AG Grid's *Value Aggregation* menu)
Configuring the aggregation via the Column Menu is a 2-step process:
- choose `Weighted Average` from the `Value Aggregation` menu item in the Column Menu in the column which you want to aggregate (`weightedAvg` must be included in the column's effective `allowedAggFuncs`)
- pick the weight column from the submenu which appears that lists every numeric column in the Grid
- The aggregation displays in column header as `weightedAvg(ValueColumn-WeightColumn)`
- e.g. a weighted average on Exam Result / Attendance produces `weightedAvg(Exam Result-Attendance)`
- Set `SuppressAggFuncInHeader` to *true* to display only the column name (same as for other aggregations)
### Filtering
The Weighted Average Aggregation evaluates using only the **currently filtered rows** in the Grid.
This follows the AG Grid pattern where aggregations take filters into account by default unless explicity configured otherwise via the `suppressAggFilteredOnly` property in Grid Options.
Set `suppressAggFilteredOnly` to *true* in Grid Options for Weighted Average aggregations to include non-filtered rows
### Hiding Weighted Average
It is possible to hide the `weightedAverage` aggregation if this is not required or useful to your users.
This is done the same way as hiding AG Grid's aggFuncs - via the `allowedAggFuncs` in each ColumnDef.
Hide `weightedAvg` aggFunc by omitting it from list of Column's aggFuncs, e.g. `allowedAggFuncs: ['sum', 'min'],`
## Weighted Average Summaries
AdapTable is able to display the Weighted Average for any selected Cells or Rows:
- For [Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising-cells/index.md) - select `weightedAvg` in the Cell Summary [Toolbars](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars), [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) or [Status Panel](https://www.adaptabletools.com/docs/ui-status-bar/index.md)
- For [Row Summary](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md) - add to the `RowSummaries` property in the Layout
- Cell and Row Summaries require the summarised Column to have an associated [Weighted Average Aggregation](#weighted-average-aggregations)
- This should be provided in the Layout's Aggregations (see above)
## Weighted Averages in Expressions
Weighted Averages can also provided in [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) by using [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md).
This is particularly useful if you wish to show Weighted Averages in a [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md)
It is achieved by providing a `WEIGHT` parameter to the `AVG` Expression Function.
The `WEIGHT` Expression Function recieves a single argument which is the name of the Column to use for weighting
```ts [[1, 2, "AVG"], [2, 2, "WEIGHT"]]
// Return Weighted Average for 'examResult' Column (using 'attendance' column for weighting)
AVG([examResult], WEIGHT([attendance]))
```
The Weighting can also be grouped if necessary by using the `GROUP_BY` Expression Function:
```ts [[1, 2, "AVG"], [2, 2, "WEIGHT"], [3, 2, "GROUP_BY"]]
// Weighted Average for 'examResult' (with 'attendance' for weighting) grouping by Class & Pupil
AVG([examResult], WEIGHT([attendance]), GROUP_BY([class], [pupil]))
```
**Example: Using Weighted Averages**
Providing Weighted Average Aggregations
- This example illustrates the different ways that Weighted Averages can be used in AdapTable:
- **Aggregation** - the `Exam Result` Column has been given a Weighted Average Aggregation, using the `Attendance` Column as the *weighted* column
- **Expression Functions**: - the `Calc Column` [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) - has an [Aggregation Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) (which includes the `AVG`, `WEIGHTED` & `GROUP_BY` functions)
- **Cell Summary** - a [Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising-cells/index.md) has been set to be `Weighted Avg` (and some cells have been highlighted for convenience)
- **Row Summary** - a [Row Summary](https://www.adaptabletools.com/docs/handbook-summarising-rows/index.md) has been added to the top of the Grid showing Weighted Average for `Exam Result` Column
- Note: the Calculated Column provides the same result as the Weighted Average Aggregation and Selected Cells Summary
### Expand to see how these 3 Weighted Average elements were set up
The Weighted Average Aggregation for the `Exam Result` Column was provided in Layout Initial State
```ts
Layout: {
CurrentLayout: 'Full Layout',
Layouts: [
{
Name: 'Full Layout',
TableColumns: ['pupil', 'subject','examResult', 'attendance', 'class', 'Calc'],
RowGroupedColumns: ['class', 'pupil'],
SuppressAggFuncInHeader: true,
TableAggregationColumns: [
{
ColumnId: 'examResult',
AggFunc: {
type: 'weightedAverage',
weightedColumnId: 'attendance',
},
}],
},
],
},
```
The [Cell Summary](https://www.adaptabletools.com/docs/handbook-summarising/index.md) Operation was set to `Weighted Avg`, row groups opened and cells highlighted using [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) methods:
```ts
adaptableApi.cellSummaryApi.setCurrentCellSummaryOperation('Weighted Avg');
adaptableApi.gridApi.expandAllRowGroups();
setTimeout(() => {
const gridCellRange: GridCellRange = {
columnIds: ['examResult'],
rowIndexStart: 2,
rowIndexEnd: 4,
};
adaptableApi.gridApi.selectCellRange(gridCellRange);
}, 100);
```
The `Calc Column` [Calculated Column](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) was defined in Calculated Column Initial State:
```ts
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'calcColumn',
FriendlyName: 'Calc Column',
Query: {
AggregatedScalarExpression: 'AVG([examResult], WEIGHT([attendance] ), GROUP_BY([class], [pupil]) ) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
]},
```
- Select the 5 cells for Andy in the `Exam Result` column and not how all the Aggregations add up
- Type 2 in the filter for the `Attendance` column (to filter the Grid) and not how the Exam Result aggregations automatically change
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'Id',
adaptableId: 'Weighted Average',
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Main',
Toolbars: ['CellSummary', 'Layout'],
},
],
ModuleButtons: ['CalculatedColumn'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['CellSummary', 'Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'calcColumn',
FriendlyName: 'Calc Column',
Query: {
AggregatedScalarExpression:
'AVG([examResult], WEIGHT([attendance] ), GROUP_BY([class], [pupil]) ) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
Layout: {
CurrentLayout: 'Full Layout',
Layouts: [
{
Name: 'Full Layout',
TableColumns: [
'pupil',
'subject',
'examResult',
'attendance',
'class',
'calcColumn',
],
RowGroupedColumns: ['class', 'pupil'],
RowSummaries: [
{
Position: 'Top',
ColumnsMap: {
examResult: 'WEIGHTED_AVERAGE',
},
},
],
SuppressAggFuncInHeader: true,
TableAggregationColumns: [
{
ColumnId: 'examResult',
AggFunc: {
type: 'weightedAverage',
weightedColumnId: 'attendance',
},
},
{
ColumnId: 'blah',
AggFunc: true,
},
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-examResult',
Scope: {
ColumnIds: ['examResult', 'calcColumn'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
headerName: 'Id',
field: 'resultId',
hide: true,
cellDataType: 'number',
},
{
headerName: 'Subject',
field: 'subject',
editable: true,
cellDataType: 'text',
enableRowGroup: true,
sortable: true,
filter: true,
resizable: true,
},
{
headerName: 'Pupil',
field: 'pupil',
editable: true,
cellDataType: 'text',
enableRowGroup: true,
sortable: true,
filter: true,
resizable: true,
},
{
headerName: 'Exam Result',
field: 'examResult',
editable: true,
cellDataType: 'number',
sortable: true,
aggFunc: 'sum',
enableValue: true,
filter: true,
resizable: true,
},
{
headerName: 'Attendance',
field: 'attendance',
editable: true,
enableValue: true,
cellDataType: 'number',
sortable: true,
filter: true,
resizable: true,
},
{
headerName: 'Class',
field: 'class',
editable: true,
enableRowGroup: true,
enableValue: true,
cellDataType: 'text',
sortable: true,
filter: true,
resizable: true,
},
];
```
```ts
export const rowData = [
{
resultId: 1,
pupil: 'Tim',
subject: 'Maths',
examResult: 40,
attendance: 3,
class: 'Year 7',
},
{
resultId: 2,
pupil: 'Tim',
subject: 'English',
examResult: 30,
attendance: 2,
class: 'Year 7',
},
{
resultId: 3,
pupil: 'Tim',
subject: 'French',
examResult: 30,
attendance: 5,
class: 'Year 7',
},
{
resultId: 4,
pupil: 'Andy',
subject: 'Maths',
examResult: 20,
attendance: 2,
class: 'Year 7',
},
{
resultId: 5,
pupil: 'Andy',
subject: 'History',
examResult: 20,
attendance: 2,
class: 'Year 7',
},
{
resultId: 6,
pupil: 'Andy',
subject: 'French',
examResult: 20,
attendance: 3,
class: 'Year 7',
},
{
resultId: 7,
pupil: 'Andy',
subject: 'English',
examResult: 10,
attendance: 3,
class: 'Year 7',
},
{
resultId: 8,
pupil: 'Andy',
subject: 'Physics',
examResult: 30,
attendance: 5,
class: 'Year 7',
},
{
resultId: 9,
pupil: 'Sally',
subject: 'English',
examResult: 20,
attendance: 3,
class: 'Year 8',
},
{
resultId: 10,
pupil: 'Sally',
subject: 'Physics',
examResult: 20,
attendance: 5,
class: 'Year 8',
},
{
resultId: 11,
pupil: 'Mark',
subject: 'English',
examResult: 10,
attendance: 3,
class: 'Year 8',
},
{
resultId: 12,
pupil: 'Mark',
subject: 'Physics',
examResult: 10,
attendance: 5,
class: 'Year 8',
},
{
resultId: 13,
pupil: 'Mark',
subject: 'Physics',
examResult: 25,
attendance: 5,
class: 'Year 8',
},
];
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
rowGroupPanelShow: 'always',
grandTotalRow: 'bottom',
statusBar: {
statusPanels: [
{
key: 'Left Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'left',
},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
{
key: 'Right Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'right',
},
],
},
suppressMenuHide: true,
cellSelection: true,
};
```
```ts
import {AdaptableReadyInfo, GridCellRange} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.cellSummaryApi.setCurrentCellSummaryOperation('Weighted Avg');
adaptableApi.gridApi.expandAllRowGroups();
setTimeout(() => {
const gridCellRange: GridCellRange = {
columnIds: ['examResult'],
rowIndexStart: 2,
rowIndexEnd: 4,
};
adaptableApi.gridApi.selectCellRange(gridCellRange);
}, 100);
};
```
---
# Displaying Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting
- AdapTable facilitates the creation of powerful and flexible Alerts
- Alerts are fired when the **Rule** specified in an **Alert Definition** is met
- This is typically the result of Data Changes in AG Grid - either a user edit or ticking data
- An Alert Rule can be either:
- a Predicate
- an Expression (either Boolean, Observable or Aggregation Boolean)
- All Alerts have a Message Type and an accompanying Message
- Once triggered, there are many options available for how the Alert should behave
Alerts are one of the most popular and powerful functionalities offered by AdapTable.
AdapTable provides 5 different types of Alerts, each with many, rich, options to help users control how to trigger, react to, and render each Alert.
## Alert Rule
Each Alert Definition has a `Rule` which defines what data change triggers the Alert.
Alert Rules can be grouped conceptually into 6 types (all are evaluated using [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)):
- Data Change
- Relative Change
- Row Change
- Observable
- Aggregation
- Validation
### Data Change
[Data Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) are the most common type of Alert.
The Alert fires when the change in a Grid Cell value matches the Alert Rule.
The Data Change that triggers the Alert can be either a user edit or a ticking update.
- Data Change Alerts contain [Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) - commonly used across AdapTable
- This allows users to specify which columns (or Data Types or Column Types) will trigger Alerts when they change
Most Data Change Alerts use [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md), a boolean function widely used in AdapTable (e.g. [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md)).
There is no limit on how many Predicates can be provided in each Alert Definition.
The [AdapTableQL Guide](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) provides details on using [System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) and creating [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md)
More complex Data Change Alerts use a [(Boolean) Standard Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) - (i.e. an Expression which returns `true`/`false`)
This allows the creation of Alerts which fire based not just on data changes in the cell, but other values in the row
### Relative Change
[Relative Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-relative-change/index.md) valuate on the relative nature of the change made to a given Cell's value.
These Alerts leverage the `ANY_CHANGE`, `PERCENT_CHANGE` and `ABSOLUTE_CHANGE` Expression Functions
### Row Change
[Row Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) fire in response to rows being added / removed in AG Grid.
These Alerts leverage the `ROW_ADDED` and `ROW_REMOVED` Observable Expression Functions
### Aggregation
[Aggregation Alerts](https://www.adaptabletools.com/docs/handbook-alerting-aggregation/index.md) run against aggregated data to fire using data from more than one row.
They leverage [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) to enable things like Limits Analysis (e.g. to fire when the sum of the 'PnL' Column is over 50M for rows where Currency is Dollar).
### Observable
[Observable Alerts](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md) use [Reactive (Rx) Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) to fire in response to specified changes in AG Grid.
These changes can be in a particular row (or set of rows) or in the entire Grid.
Observable Alerts can also react to a lack of changes, i.e. if something doesnt tick in a given amount of time
### Scheduled
[Scheduled Alerts](https://www.adaptabletools.com/docs/handbook-alerting-schedule/index.md) fire according to a set Schedule.
The Alert is fired with the message provided in the Alert Definition and can be scheduled as a one off Alert or on a recurring basis (e.g. weekly or monthly).
### Validation
[Validation Alerts](https://www.adaptabletools.com/docs/handbook-alerting-validation/index.md) prevent data changes that break an Alert Rule.
The data change is rolled back before the cell edit is committed.
## Alert Message Type
Each Alert has a `MessageType` property which influences how the Alert is rendered.
This includes in the Alert Toolbar, Tool Panel, Status Bar and in any [Toast Notifications](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
Four [`Message Types`](https://www.adaptabletools.com/docs/reference/adaptablemessagetype.md) are available. Each has a different associated colour (configurable through [CSS Variables](https://www.adaptabletools.com/docs/handbook-theming-custom/index.md)) that is used by when rendering the Alert Notification.
| Message Type | Default Colour and CSS Variable |
| ------------ | ---------------------------------------------------------------------------------------------------------------------- |
| Info |
var(--ab-color-info)
|
| Success |
var(--ab-color-success)
|
| Warning |
var(--ab-color-warn)
|
| Error |
var(--ab-color-destructive)
|
The colour returned by any of these variables can be set when [Customising an AdapTable Theme](https://www.adaptabletools.com/docs/handbook-theming-custom/index.md)
## Alert Behaviours
There are many behaviours that can be set for an Alert including:
- **Display a Notification** - probably the most common Alert Behaviour: AdapTable displays a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) (with an optional Form or Action buttons) when an important Alert fires
- **Highlight the Cell (or Row)** where the data changed that triggered the Alert
- **Jump to Cell** so AG Grid immediately shows the row which contains the cell that triggered the Alert
- **Show the Alert details** in a bespoke Div element (that you specify in [Container Options](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-containers/index.md))
- **Prevent the Cell Edit** from happening when they break the rule set in the [Alert Definition](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
- **Log to the Console** a message detailing the Data Change and the Alert Definition
- AdapTable **always** displays a message in the Alert [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md), [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) or [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md)
- It also always triggers the [Alert Fired Event](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md) providing full details of the Data Change and Alert Definition
[Alert Behaviours](https://www.adaptabletools.com/docs/handbook-alerting-behaviours/index.md) contains more information on the Alert Behaviours available
## Alert Forms
Alert Notifications can additionally include fully customisable **Forms**.
These are instances of [Adaptable Forms](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) (similar to those used in [Custom Export Destinations](https://www.adaptabletools.com/docs/handbook-exporting-destinations-custom/index.md)) that can be configured to show bespoke form elements.
### Alert Button Actions
Alert Forms can be wired so that Alert Button Actions are triggered when the Form's Button is clicked.
- [Alert Behaviours](#alert-behaviours) trigger when the Alert itself is fired
- Alert Button Actions trigger when a Button in an Alert Form is clicked
AdapTable provides System Alert Button Actions which are available to end-users when creating an Alert in the AdapTable UI.
In addition developers can supply their own bespoke Custom Alert Button Actions.
See [Providing an Alert Form](https://www.adaptabletools.com/docs/handbook-alerting-notifications/index.md) for full details of these potentially complicated topics
## Using Alerts
Run-time access to Alerts is available in the Alert section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md).
This lists all Alerts in Adaptable State together with options to Create, Edit, Delete and Suspend.
### Suspending Alerts
Like most [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects), Alerts can be suspended by clicking the toggle button in the Settings Panel.
When an Alert is suspended it is fully cancelled: no Alert Messages will be fired, no toast notifications will display and nothing will show in the Alert Toolbar and Tool Panel.
If it is a [Reactive (i.e. Observable) Alert](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md), then the subscription is **removed** when the Alert is suspended and will be re-created when unsuspended.
- Set `DisplayNotification` to false in `Alert Properties` to keep the Alerts running but reduce notifications
- Alternatively change the default notification behaviour in [Notification Options](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
## UI Entitlements
The UI Entitlements behaviour is as expected for Full and Hidden `Access Levels`.
The `ReadOnly` Entitlement behaviour is that Alerts will trigger as normal but users cannot create, edit, delete or suspend Alert Definitions; Alerts may be still cleared however.
---
# Aggregation Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-aggregation
- Aggregation Alerts can use Aggregation Boolean Expressions
- These will evaluate using multiple rows and fire if the return value is true
Alerts in AdapTable can fire as the result of an [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md).
This is a special type of Expression which runs against **aggregated data** and returns a true / false value.
For instance to define an Alert which fires when the total of a 'PnL' column is > 50M:
```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "50M"]]
// Is the sum of all PnL values over 5M
SUM([PnL]) > '50M'
```
## Aggregation Functions
Currently 5 Aggregation Functions are supported:
- `SUM`
- `MIN`
- `MAX`
- `AVG`
- `COUNT`
Aggregation Expressions require the Alert to have a [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of `All` (i.e. the whole row)
The [AdapTableQL Guide](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) provides full details on writing [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md)
## WHERE Clause
Aggregation Alerts often have a `WHERE` clause which limits which rows are included in the evaluation.
For instance to define the Alert above, but only in rows with a Dollar Currency we would write:
```ts [[1, 2, "SUM"],[2, 2, "PnL"],[3, 2, ">"],[4, 2, "50M"],[5, 2, "WHERE [Currency] = 'USD'"]]
// Are all PnL values in rows with Dollar Currency over 5M
SUM([PnL]) > '50M' WHERE [Currency] = 'USD'
```
**Example: Alerts: Aggregated Expressions**
Alerts fired due to Aggregated Boolean Expressions
- This demo contains 4 Alerts that fire when an Aggregated Boolean Expression is triggered
- `Info` Alert if the lowest `Github Watchers` values is under 50
- `Success` Alert when the total of all the `Github Stars` rows is over 10,000
- `Warning` Alert when the total of all `Open Issues` - **only** for rows where Language is JavaScript - is over 6,000
- `Error` Alert when the count of all `Language` is 3 or greater where value is 'HTML'
- In the first row change the value of:
- `Github Watchers` column to 45 and see the `Info` Alert be fired
- `Github Stars` column to 279429 and see the `Success` Alert be fired
- `Open Issues` column to 1220 and see the `Warning` Alert be fired (because `Language` in first row is "JavaScript")
- `Language` column to *HTML* and see the `Error` Alert be fired (because we now have 3 values with HTML)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Aggregated Boolean Expression Alert',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert', 'CellSummary'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-watchers',
MessageType: 'Info',
Scope: {
All: true,
},
Rule: {
AggregatedBooleanExpression: 'MIN([github_watchers] ) < 50 ',
},
AlertProperties: {
DisplayNotification: true,
},
},
{
Name: 'alert-github-stars',
MessageType: 'Success',
Scope: {
All: true,
},
Rule: {
AggregatedBooleanExpression: "SUM([github_stars] ) > '10k' ",
},
AlertProperties: {
DisplayNotification: true,
},
},
{
Name: 'alert-open-issues-count',
MessageType: 'Warning',
Scope: {
All: true,
},
Rule: {
AggregatedBooleanExpression:
"SUM([open_issues_count] ) >'6k' WHERE [language] = 'JavaScript' ",
},
AlertProperties: {
DisplayNotification: true,
},
},
{
Name: 'alert-language',
MessageType: 'Error',
Scope: {
All: true,
},
Rule: {
AggregatedBooleanExpression:
"COUNT([language] ) >= 3 WHERE [language] = 'HTML' ",
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_watchers',
'license',
'github_stars',
'open_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Listening to Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-alert-fired-event
- Event published by AdapTable whenever an [Alert](https://www.adaptabletools.com/docs/handbook-alerting/index.md) has been triggered by AdapTable
- Provides details of the Alert that fired and the Alert Definition that triggered it
The **Alert Fired Event** is published by AdapTable whenever an Alert is fired.
The `EventInfo` includes full details of the Alert Definition that triggered the Alert, the Change that occurred in AG Grid and other related information.
The Change that can be triggered the Alert can be one of 2 types:
- `Cell Change` - the value of a Cell has changed
- `Row Change` - a row has been added, updated, or deleted
### Understanding the Alert Fired Event
**AlertFiredInfo**
The event comprises the [`AlertFiredInfo`](https://www.adaptabletools.com/docs/reference/alertfiredinfo.md) object which contains a single property:
| Property | Type | Description |
| --- | --- | --- |
| [alert](https://www.adaptabletools.com/docs/reference/alertfiredinfo.md#alert) | [`AdaptableAlert`](https://www.adaptabletools.com/docs/reference/adaptablealert.md) | Alert which has been fired |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/alertfiredinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
This is of type [`AdaptableAlert`](https://www.adaptabletools.com/docs/reference/adaptablealert.md) which has 2 flavours:
- Cell Changed Alert
- Row Changed Alert.
**Cell Changed Alert**
This is fired when a Cell in AdapTable is changed - either manually or via ticking data.
It is of type [`AdaptableCellChangedAlert`](https://www.adaptabletools.com/docs/reference/adaptablecellchangedalert.md) and contains a single `cellDataChangedInfo` property:
| Property | Type | Description |
| --- | --- | --- |
| [cellDataChangedInfo](https://www.adaptabletools.com/docs/reference/adaptablecellchangedalert.md#celldatachangedinfo) | [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md)`` | Cell DataChange which triggered Alert |
This property is of type [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md) and contains full details of the Cell Change:
| Property | Type | Description |
| --- | --- | --- |
| [changedAt](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#changedat) | `number` | Timestamp of change occurrence (in milliseconds) |
| [column](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#column) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`` | Column in which cell is situated |
| [newValue](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#newvalue) | `any` | New value for the cell |
| [oldValue](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#oldvalue) | `any` | Value in the Cell before the edit |
| [preventEdit](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#preventedit) | `boolean` | Whether the change was prevented by a validation rule |
| [primaryKeyValue](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#primarykeyvalue) | `any` | Primary Key Column's value for the row where edited cell is situated |
| [rowData](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#rowdata) | `TData` | Data in the Row |
| [rowNode](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#rownode) | `IRowNode` | AG Grid RowNode that contains the cell |
| [trigger](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md#trigger) | `'edit' \| 'tick' \| 'undo' \| 'aggChange' \| 'calculatedColumnChange'` | What triggered the change - user, background change, a reverted change, or a derived update on a Calculated Column whose source value changed? |
**Row Changed Alert**
This is fired when a Row in AdapTable has been added, updated or deleted.
It is of type [`AdaptableRowChangedAlert`](https://www.adaptabletools.com/docs/reference/adaptablerowchangedalert.md) and contains a single `rowDataChangedInfo` property:
| Property | Type | Description |
| --- | --- | --- |
| [rowDataChangedInfo](https://www.adaptabletools.com/docs/reference/adaptablerowchangedalert.md#rowdatachangedinfo) | [`RowDataChangedInfo`](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md)`` | Row DataChange which triggered Alert |
This property is of type [`RowDataChangedInfo`](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md) and contains full details of the Row in question:
| Property | Type | Description |
| --- | --- | --- |
| [changedAt](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md#changedat) | `number` | Timestamp of change occurrence (in milliseconds) |
| [dataRows](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md#datarows) | `TData[]` | Data rows that have been added, updated, or deleted |
| [rowNodes](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md#rownodes) | `IRowNode[]` | Row Nodes that were affected by this change |
| [rowTrigger](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md#rowtrigger) | [`RowDataChangeTrigger`](https://www.adaptabletools.com/docs/reference/rowdatachangetrigger.md) | Trigger for row change: Load, Add, Update, or Delete |
**Event Subscription**
Subscribing to the Event is done the same way as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md):
```ts
api.eventApi.on('AlertFired', (eventInfo: AlertFiredInfo) => {
// do something with the info
});
```
**Example: Events: Alert Fired**
Event published when Alerts fire
- This Demo listens to the Alert Fired Event and sends details as a System Status Message. There are 2 Alerts:
- **Cell Changed**: `Error` Alert if *GitHub Stars* Column is `LessThan` 1000
- **Row Changed**: `Warning` Alert when a Row is deleted
- Trigger Alerts and then see how the Alert Fired Event is handled by:
- Editing a cell in the _GitHub Stars_ Column to a value `<1000`
- Clicking the Delete Row Button
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Alert Fired Event Demo',
actionColumnOptions: {
actionColumns: [
{
columnId: 'action',
friendlyName: 'Delete',
actionColumnButton: {
command: 'delete',
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert', 'SystemStatus'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert', 'SystemStatus'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-error-github-stars',
MessageType: 'Error',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'LessThan',
Inputs: [1000],
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
{
Name: 'alert-warning-row-removed',
Rule: {
ObservableExpression: 'ROW_REMOVED()',
},
MessageType: 'Warning',
MessageHeader: 'You removed a row',
MessageText: 'Hey! A row was removed',
Scope: {
All: true,
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'action',
'name',
'language',
'github_stars',
'license',
'open_issues_count',
'description',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
import {AdaptableMessageType, AlertFiredInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.eventApi.on('AlertFired', (alertFiredInfo: AlertFiredInfo) => {
const messageType: AdaptableMessageType =
alertFiredInfo.alert.alertDefinition.MessageType;
if (messageType == 'Info') {
adaptableApi.systemStatusApi.setInfoSystemStatus(
alertFiredInfo.alert.alertType,
alertFiredInfo.alert.alertDefinition.MessageHeader
);
} else if (messageType == 'Success') {
adaptableApi.systemStatusApi.setSuccessSystemStatus(
alertFiredInfo.alert.alertType,
alertFiredInfo.alert.alertDefinition.MessageHeader
);
} else if (messageType == 'Warning') {
adaptableApi.systemStatusApi.setWarningSystemStatus(
alertFiredInfo.alert.alertType,
alertFiredInfo.alert.alertDefinition.MessageHeader
);
} else if (messageType == 'Error') {
adaptableApi.systemStatusApi.setErrorSystemStatus(
alertFiredInfo.alert.alertType,
alertFiredInfo.alert.alertDefinition.MessageHeader
);
}
});
};
```
---
# Alert Behaviours
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-behaviours
- AdapTable provides many options for how an Alert should behave once it is triggered, including:
- highlighting and / or jumping to the triggering cell or row
- showing a Notification (which can include custom forms and multiple action buttons)
All Alerts, when they are triggered, will perform 2 actions:
1. Display in the Alert [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md), [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) or [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) (including a running count of Alerts fired)
2. Trigger the [Alert Fired Event](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md) providing full details of the Data Change and Alert Definition
But there are many other behaviours that can be set for an Alert including:
- **Display a Toast Notification** - probably the most common Alert Behaviour: AdapTable displays a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) (with an optional Form or Action buttons) when an important Alert fires
- The default value of 3 seconds can be changed in the `duration` property of [Notifications Options](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
- Set this to `always` to ensure notifictions need to be manually dismissed
- **Highlight the Cell (or Row)** where the data changed that triggered the Alert
- **Jump to Cell (or Row)** so AG Grid displays the row which contains the cell that triggered the Alert
- **Show the Alert details** in a bespoke Div element (that you specify in [Container Options](https://www.adaptabletools.com/docs/dev-guide-tutorial-providing-containers/index.md))
- **Prevent the Cell Edit** from happening when they break the rule set in the [Alert Definition](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
- This is described in more detail in [Validation Alerts](https://www.adaptabletools.com/docs/handbook-alerting-validation/index.md)
- **Log to the Console** a message detailing the Data Change and the Alert Definition
**Example: Alerts: Alert Behaviours**
Alerts configured with particular Behaviours
- This demo fires an Alert when any value in `Github Stars` column is changed.
- The Alert Definition is configured with these behaviours wen the Alert is triggered:
- Highlights the Cell that triggered the Alert using the Alert's `Message Type` colour (here Orange for `Warning`)
- Highlights the Row that triggered the Alert using a custom [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) (white on purple)
- Jumps to the Cell which triggered the Alert
- We set the `rowHighlightDuration` and `cellHighlightDuration` properties to 3 and 1.5 seconds respectively to see the changes better
### Expand to see the Alert Definition
Set the Row and Cell Highlight Durations in Alert Options
```ts
alertOptions: {
rowHighlightDuration: 3000,
cellHighlightDuration: 1500,
}
```
Provide the Alert Definition - together with Behaviours - in Alert Initial Adaptable State
```ts
Alert: {
AlertDefinitions: [
{
Name: 'alert-any-change',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
AlertProperties: {
HighlightCell: true, // will highlight it using the Alert's Message Type
HighlightRow: {
BackColor: 'Purple',
ForeColor: 'White',
},
JumpToCell: true,
},
},
],
},
```
- Click the `Update First Row` or `Update Last Row` [Custom Toolbar Buttons](https://www.adaptabletools.com/docs/ui-dashboard-technical-reference/index.md) to trigger the Alert and see the Behaviours
```ts
import {
CellUpdateRequest,
CustomRenderContext,
} from '@adaptabletools/adaptable';
import {
AdaptableButton,
AdaptableOptions,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {IRowNode} from 'ag-grid-enterprise';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Alert Behaviours',
alertOptions: {
rowHighlightDuration: 3000,
cellHighlightDuration: 1500,
},
dashboardOptions: {
customToolbars: [
{
name: 'ButtonToolbar',
title: 'Buttons',
toolbarButtons: [
{
label: 'Update First Row',
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const primaryKeyValue = 10270250; // 43695474
const firstNode: IRowNode =
context.adaptableApi.gridApi.getRowNodeForPrimaryKey(
primaryKeyValue
);
const githubStars = firstNode.data['github_stars'];
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: githubStars + 1,
primaryKeyValue: primaryKeyValue,
rowNode: firstNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
{
label: 'Update Last Row',
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const primaryKeyValue = 43695474;
const lastNode: IRowNode =
context.adaptableApi.gridApi.getRowNodeForPrimaryKey(
primaryKeyValue
);
const githubStars = lastNode.data['github_stars'];
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: githubStars + 1,
primaryKeyValue: primaryKeyValue,
rowNode: lastNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
buttonStyle: {
tone: 'info',
variant: 'text',
},
},
],
},
{
name: 'BespokeRenderingToolbar',
title: 'Bespoke Rendering',
render: (customRenderContext: CustomRenderContext) => {
if (customRenderContext.phase === 'onMount') {
return `
`;
}
return null;
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert', 'ButtonToolbar'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-any-change',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
AlertProperties: {
HighlightCell: true, // will highlight it with Message Type
HighlightRow: {
BackColor: 'Purple',
ForeColor: 'White',
},
JumpToCell: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Configuring Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-configuring
- Alerts can be provided at design-time through Alert Initial State
- The Alert Options section of Adaptable Options contains many properties for configuring Alert behaviour
Developers are able to provide Alert Definitions and configure Alerts behaviour at design-time.
## Alert Definitions
Alert Definitions can be provided in [Alert Initial State](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md) or created at run-time
This will ensure that the Alerts will fire as necessary each time the Application loads, and that any changes will be stored with Adaptable State.
## Alert Options
There are many options in [Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md) that can be set to manage the behaviour of Alerts.
### Highlight Duration
Developers can set the highlight durations for Rows, Cells and the Alert Status Bar Panel.
### `cellHighlightDuration`
How long (in ms) a Cell will be highlighted when an Alert fires
One of the [Alert Behaviours](https://www.adaptabletools.com/docs/handbook-alerting/index.md#alert-behaviours) that can be provided for an Alert is to highlight the Cell which caused the Alert to fire.
This is set in miliseconds and defaults to 2000 (i.e. 2 seconds) but can be changed in this property.
```ts {4}
// Set Cells to be Highlighted for 4 seconds when an Alert is fired with behaviour of 'Highlight Cell'
const adaptableOptions: AdaptableOptions = {
alertOptions: {
cellHighlightDuration: 4000,
},
};
```
### `rowHighlightDuration`
How long (in ms) a Row will be highlighted when an Alert fires
One of the [Alert Behaviours](https://www.adaptabletools.com/docs/handbook-alerting/index.md#alert-behaviours) that can be provided for an Alert is to highlight the Row which contains the Cell that caused the Alert to fire.
This is set in miliseconds and defaults to 4000 (i.e. 4 seconds) but can be changed in this property.
```ts {4}
// Set Rows to be Highlighted for 5 seconds when an Alert is fired with behaviour of 'Highlight Row'
const adaptableOptions: AdaptableOptions = {
alertOptions: {
rowHighlightDuration: 5000,
},
};
```
### `statusbarHighlightDuration`
How long (in ms) Alert panel in Status Bar is highlighted when an Alert Fires
If the Alert Status Panel has been supplied to the [AdapTable Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) it will be highlighted when an Alert fires.
The Highlight colour will be in accordance with the Message Type of the Alert
The duration of the Highlight defaults to 2000 miliseconds (i.e. 2 seconds) but this can be changed in this property.
```ts {4}
// Set Alert Status Panel in Status Bar to be Highlighted for 5 seconds when an Alert is fired
const adaptableOptions: AdaptableOptions = {
alertOptions: {
statusbarHighlightDuration: 5000,
},
};
```
### Highlight Style
This defaults to the Alert's `MessageType` colour but you can provide an [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) instead
### Cell Change Behaviour
Developers can configure the cell change behaviour for triggering Alerts
### `dataChangeDetectionPolicy`
Whether an Alert rule is evaluated against the rawValue or formattedValue of the changed cell data
By default AdapTable will trigger an Alert if the change in a cell's raw value triggers the Rule provided in the Alert Definition.
This can sometimes cause excessive Alerts e.g. if the 5th decimal place in cell value changes for a currency amount which essentially stays the same.
In this case, set this property to `formattedValue` and the Alert will only trigger if the value displayed in the Cell changes.
```ts {4}
// Set Alerts to trigger only when the Cell's Display (and not underlying) value changes
const adaptableOptions: AdaptableOptions = {
alertOptions: {
dataChangeDetectionPolicy: 'formattedValue',
},
};
```
### Number of Alerts Saved
### `maxAlertsInStore`
How many triggered Alerts are held in State at any one time
AdapTable caches Alerts when they are fired in the Grid (as the result of an Alert Definition being triggered).
It will store up to 20 Alerts - so when the limit is breached, the oldest Alert will be removed.
This property can be used to configure for a different number of Alerts to be stored.
```ts {4}
// Cache 50 Alerts (instead of default of 20)
const adaptableOptions: AdaptableOptions = {
alertOptions: {
maxAlertsInStore: 50,
},
};
```
---
# Data Change Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-data-change
- The most common type of Alerts in AdapTable are those which fire as the result of a Data Change rule
- This Data Change rule can be one of 2 types:
- A Predicate - fires when the cell change matches the predicate
- A Boolean Expression - allows for multiple cell values to be included in the evaluation
Data Change Alerts are the most common type of Alert in AdapTable.
They fire whenever a change in the Grid's data matches the Rule in the Alert Definition.
This change can be either the result of a user's edit or of ticking data
The Rule can be one of two types:
- [Predicate](#predicate)
- [Expression](#boolean-expression)
## Predicate
[Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) are used for more "simple" Data Change based Alert rules.
A Predicate is a boolean function used in many places in AdapTable (e.g. [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md))
Predicates have a type (e.g. `GreaterThan`, `Positive`) and optional inputs if required (e.g. `100`).
See the [System Predicate Guide](https://www.adaptabletools.com/docs/adaptable-predicate-system/index.md#system-predicate-list) for a list of all the System Predicates available for Alerts
The Alert fires if the Data Change matches that defined in the Predicate.
**Example: Alerts: Triggered by Predicates**
Alerts fired due to Predicate Rules
- This Demo contains 4 Alerts that each uses a Predicate-based Rule for reacting to Data Changes:
- `LessThan` Predicate (on the *GitHub Stars* Column) - the Alert fires if the value is less than `1000`
- `GreaterThan` Predicate (on the *Open Issues* Column) - the Alert fires if the value is greater than `500`
- `Blank` Predicate (on all *String* Columns) - the Alert fires if the new cell value in any string Column is empty
- `Is` Predicate (on the *Name* Column) - the Alert fires if the `Name` is changed to "Python"
- Each Alert will display a Notification and has a Behaviour of highlighting the cell
### Expand to see the Predicate Definitions
- `LessThan` Predicate (on the _GitHub Stars_ Column) - the Alert fires if the value is less than `1000`
```ts
Rule: {
Predicates: [{
PredicateId: 'LessThan',
Inputs: [1000],
}],
}
```
- `GreaterThan` Predicate (on the _Open Issues_ Column) - the Alert fires if the value is greater than `500`
```ts
Rule: {
Predicates: [{
PredicateId: 'GreaterThan',
Inputs: [500],
}],
}
```
- `Blank` Predicate (on all _String_ Columns) - the Alert fires if the new cell value in any string Column is empty
```
Rule: {
Predicates: [{
PredicateId: 'Blanks',
}],
}
```
- `**Name**` Predicate (on the _Name_ Column) - the Alert fires if the name is changed to Python
```
Rule: {
Predicates: [{
PredicateId: 'Is',
Inputs: ['Python']
}],
}
```
- Trigger Alerts by:
- Editing a cell in the _GitHub Stars_ Column to a value `<1000`
- Editing a cell in the _Open Issues_ Column to a value `>500`
- Changing a value in _Language_, _Name_ or _Description_ Columns to a blank value
- Changing a value in the _Name_ Column to "Python"
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Basic Alerts',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'LessThan',
Inputs: [1000],
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
{
Name: 'alert-open-issues-count',
MessageType: 'Success',
Scope: {
ColumnIds: ['open_issues_count'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [500],
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
{
Name: 'alert-info',
MessageType: 'Info',
Scope: {
DataTypes: ['text'],
},
Rule: {
Predicates: [
{
PredicateId: 'Blanks',
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
{
Name: 'alert-name',
MessageType: 'Error',
Scope: {
ColumnIds: ['name'],
},
Rule: {
Predicates: [
{
PredicateId: 'Is',
Inputs: ['Python'],
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'license',
'open_issues_count',
'description',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
],
AutoSizeColumns: true,
},
],
},
},
};
```
### Multiple Predicates
Prior to [Version 14](https://www.adaptabletools.com/support/version-14-release-note) only a single Predicate could be supplied for each Data Change Alert.
There is now no limit on how many Predicates can be provided in each Alert Rule.
This allows for a more powerful and flexibile rules to be set.
It allows users to use Predicates in preference to more complicated (and sometimes off-putting) Expressions
**Example: Alerts: Multiple Predicates**
Alerts fired due to Rules with Multiple Predicates
- This Demo contains 2 Alerts that each contain Multiple Predicates in the Rule which reacts to Data Changes:
- *GitHub Stars* Column - Alert fires if new value matches Predicates `GreaterThan` 100 and `LessThan` `1000`
- *Name* Column - Alert fires if new value matches Predicates `StartsWith` 'A' and `EndsWith` 'Z'
- Each Alert will display a Notification and has a Behaviour of highlighting the cell
- Trigger Alerts by:
- Editing a cell in the _GitHub Stars_ Column between 100 and 1000
- Changing a cell in _Name_ Column to a new value which starts with 'A' and ends with 'Z'
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Multiple Predicate Alerts',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [100],
},
{
PredicateId: 'LessThan',
Inputs: [9000],
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
{
Name: 'alert-name',
MessageType: 'Error',
Scope: {
ColumnIds: ['name'],
},
Rule: {
Predicates: [
{
PredicateId: 'StartsWith',
Inputs: ['A'],
},
{
PredicateId: 'EndsWith',
Inputs: ['Z'],
},
],
},
AlertProperties: {
HighlightCell: true,
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'license',
'open_issues_count',
'description',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Boolean Expression
For more advanced scenarios, Alerts can be triggered as the result of a [Standard Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md).
AdapTabble will use [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) - its native Query Language - to evaluate the Expression.
This enables Alerts which will fire based not just on data changes in the changed cell, but other values in the row
If all (the potentially complex) conditions return `true`, the Alert will fire.
- An Expression with a [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of `All` (i.e. the whole row) is evaluated whenever any cell in the row is edited
- However, specifying a limited [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of a few `ColumnIds` will restrict the edits that potentially trigger the Alert
**Example: Alerts: Boolean Expressions**
Alerts fired due to complex Boolean Expressions
- This example fires a `Success` Alert when as a result of data changes in the row, `Github Stars` has an even number and the `Language` is TypeScript
- The Boolean Expression provided is `[github_stars] % 2 = 0 AND [language] = "TypeScript"`
- Edit the _GitHub Stars_ in a row where `language=TypeScript` to be an even number
- Edit any cell in a row where `language=TypeScript` and an _even_ number of _GitHub Stars_
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Boolean Expression Alert',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-success-github-stars',
MessageType: 'Success',
Scope: {
All: true,
},
Rule: {
BooleanExpression:
'[github_stars] % 2 = 0 AND [language] = "TypeScript"',
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
The [AdapTableQL Guide](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) provides full details on writing [Boolean Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md)
---
# Alert Forms
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-forms
- AdapTable Alerts can include fully defined Forms in the Notifications
- These Forms can include as many inputs, buttons and other UI controls as needed
An Alert Definition can be configured so that a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) is displayed whenever the Alert fires.
By default the Notification will display the [Alert's Message](https://www.adaptabletools.com/docs/handbook-alerting-message/index.md) - the Header and Text that describe the Alert.
However, additionally, the Notification can be configured to render also an **Alert Form**.
This is a fully-featured, UI-rich [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md), containing multiple inputs and controls (with validation).
For uses cases where a Form is "overkill", a set of [Alert Command Buttons](https://www.adaptabletools.com/docs/handbook-alerting-notifications/index.md) can be configured instead
An Alert Form can only be configured by developers at design-time, and requires a 2-step process:
1. The Form is configured in full in the `alertForms` section of [Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
2. The Form is referenced by name in the `AlertForm` property of the [`Alert Definition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) in [Alert Initial State](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
The [Adaptable Form Guide](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) has full instructions on configuring dynamic Forms with multiple inputs and validation
### `alertForms`
Fully configured Forms to show in Alert Notifications
[`AlertForm[]`](https://www.adaptabletools.com/docs/reference/alertform.md)
Alert Notifications can contain an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) with multiple inputs and buttons.
```ts {1}
alertForms: [
{
name: 'setStars',
form: {
fields: [
{
fieldType: 'number',
label: 'Stars',
name: 'github_stars',
},
],
buttons: [
{
label: 'Set',
disabled: (_button, context) => {
if (!context.formData?.github_stars) {
return true;
}
const value = Number(context.formData?.github_stars);
return value <= 0 || isNaN(value);
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert = context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: cellChangedInfo.column.columnId,
newValue: Number(context.formData?.github_stars),
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
{
label: 'Cancel',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert = context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: cellChangedInfo?.oldValue,
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
],
},
},
],
```
**Example: Adaptable Forms in Alerts**
Alerts can display an Adaptable Form when triggered
- This demo displays an Alert Form when a cell in `Github Stars` column is given a negative value
- The Form contains 3 elements:
- a numeric input which will receive the new value for the Cell
- a `Set` button - which will replace the 0 in the Cell with the value provided in the input
- a `Cancel` Button - which will revert the Cell to its initial value
### Expand to see the Alert Form definition
The Form is defined in Alert Options:
```ts {7,10-11}
alertOptions: {
alertForms: [
{
name: 'setStars',
form: {
fields: [
{
fieldType: 'number',
label: 'Stars',
name: 'github_stars',
},
],
buttons: [
{
label: 'Set',
disabled: (_button, context) => {
if (!context.formData?.github_stars) {
return true;
}
const value = Number(context.formData?.github_stars);
return value <= 0 || isNaN(value);
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert = context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: cellChangedInfo.column.columnId,
newValue: Number(context.formData?.github_stars),
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
{
label: 'Cancel',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert = context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: cellChangedInfo?.oldValue,
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
],
},
},
],
},
```
The `Alert` section of `initialState` is configured with an Alert Definition that has an `AlertForm` property set to `'setStars'`:
```ts {17}
Alert: {
AlertDefinitions: [
{
Name: 'alert-warning',
MessageType: 'Warning',
MessageHeader: 'Github Stars Cannot be Negative',
MessageText: 'Provide a new value for Github Stars, or click "Cancel" to undo',
Scope: { ColumnIds: ['github_stars'], },
Rule: {
Predicates: [
{
PredicateId: 'Negative',
},
],
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
AlertForm: 'setStars',
},
],
},
```
The Notification duration is set to `always` so the popup can only be dismissed by the user pressing one of the two buttons in the Alert Form:
```ts
notificationsOptions: {
// this can be a number (duration in millis) or the string 'always'
duration: 'always',
},
```
- Set a `GitHub Stars` cell to a negative value and see the Alert Form appear with the input and the 2 buttons
- Provide a new value and click 'Set' and note how the cell updates
- Click 'Cancel' and note how the cell reverts to the initial value
```ts
import {
AdaptableCellChangedAlert,
AdaptableOptions,
CellDataChangedInfo,
CellUpdateRequest,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Alert Form',
notificationsOptions: {
// this can be a number (duration in millis) or the string 'always'
duration: 'always',
},
alertOptions: {
alertForms: [
{
name: 'setStars',
form: {
fields: [
{
fieldType: 'number',
label: 'Stars',
name: 'github_stars',
},
],
buttons: [
{
label: 'Set',
disabled: (_button, context) => {
if (!context.formData?.github_stars) {
return true;
}
const value = Number(context.formData?.github_stars);
return value <= 0 || isNaN(value);
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert =
context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: cellChangedInfo.column.columnId,
newValue: Number(context.formData?.github_stars),
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
{
label: 'Cancel',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert: AdaptableCellChangedAlert =
context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: cellChangedInfo?.oldValue,
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
],
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Warning',
MessageHeader: 'Github Stars Cannot be Negative',
MessageText:
'Provide a new value for Github Stars, or click "Cancel" to undo',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'Negative',
},
],
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
AlertForm: 'setStars',
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Alert Message
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-message
- AdapTable dynamically creates an Alert Message (containing Header and Text) each time an Alert is triggered
- This Alert Message can be overridden by users who can provide custom text; this can be done in 2 ways:
- via the Alert Definition
- using Alert Options
When an Alert fires, AdapTable provides an accompaying message describing why it was triggered.
This Alert Message - is created by AdapTable automatically - and is formed of 2 parts:
- Alert **Header** - a brief description of the Alert
- Alert **Text** - more information about what took place to trigger the Alert
- The Alert Message is displayed in **all** the Alert related UI controls
- i.e. in the Toolbar, Tool Panel, Status Bar - and most notably in the [Alert Notification](https://www.adaptabletools.com/docs/handbook-alerting-notifications/index.md)
## Custom Alert Message
As noted above, AdapTable will create the Alert Message automatically, based on the Alert Definition and the action that triggered the Alert.
However users are able to **override** this behaviour and to supply a custom Alert Message.
This bespoke Alert Message can be provide in 2 different ways:
- as properties in the Alert Definition (run-time or design-time)
- via a function in Alert Options (design-time only)
### Alert Definition
The most straightforward way to override the automated Alert Message is via the Alert Definition.
There are 2 properties that can be provided:
- `MessageHeader` - allows a custom Header to be displayed
- `MessageText` - allows custom Text to be shown in the Message
These properties are available both to the developer at design time and the end user at run-time
**Example: Custom Alert Messages (Definition)**
Providing Custom Alert Message via Alert Definition
- This demo shows how to provide a Custom Alert Message Header and Text using the Alert Definition
- A `Warning` Alert fires any time a value is changed in the `Language` Column
- We provide a Custom Header and Message in the Alert Definition
### Expand to see the Alert Definition
```ts
Alert: {
AlertDefinitions: [
{
Name: 'alert-language',
MessageType: 'Warning',
Scope: {
ColumnIds: ['language'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
MessageHeader: 'A Change was made!!!',
MessageText: 'The user just changed the value in the Language Column',
AlertProperties: {
DisplayNotification: true,
},
},
],
},
```
- Edit a cell in the `Language` Column and see the Alert with the custom Header and Text messages
- Note: The text displayed is the same every time the Alert fires (regardless of the row)
```ts
import {AdaptableOptions, AlertMessageContext} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Alert Message - Definition',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-language',
MessageType: 'Warning',
Scope: {
ColumnIds: ['language'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
MessageHeader: 'A Change was made!!!',
MessageText: 'The user just changed the value in the Language Column',
AlertProperties: {
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: ['name', 'language', 'license', 'has_wiki'],
},
],
},
},
};
```
### Messages using Templates
The Custom Alert Message in the Alert Definition can be provided with Template Literals.
AdapTable automatically **replaces** these templates, using string interpolation, with the relevant text when the Alert Message displays.
This enables the Alert Message to display "dynamic" content, that changes for each Alert.
Template Literals can be used in both parts of the Alert Message: Header and Text
AdapTable provides two sets of Message Templates - one which can be used in both [Data Change](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) and [Aggregation](https://www.adaptabletools.com/docs/handbook-alerting-aggregation/index.md) Alerts, and the other which is designed for [Row Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md):
| Template Literal | Description | Data Change & Aggregation | Row Change |
| ------------------- | ------------------------------------------------------------------------------------------------------------- | :-----------------------: | :--------: |
| `[newValue]` | New value for changed cell | ✅ | ❌ |
| `[oldValue]` | Old value for changed cell | ✅ | ❌ |
| `[column]` | Name of Changed Column | ✅ | ❌ |
| `[primaryKeyValue]` | Primary Key value of Row | ✅ | ❌ |
| `[timestamp]` | Timestamp when Alert triggered | ✅ | ✅ |
| `[trigger]` | What caused Alert to fire | ✅ | ✅ |
| `[numberOfRows]` | Count of Rows added or deleted | ❌ | ✅ |
| `[rowData.x]` | Changed Row (e.g. `[rowData.price]`) | ✅ | ❌ |
| `[context.x]` | Any [AG Grid context](https://www.ag-grid.com/javascript-data-grid/context/) provided (e.g. `[context.name]`) | ✅ | ✅ |
- `[trigger]` values that can be returned for [Data Change](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) & [Aggregation](https://www.adaptabletools.com/docs/handbook-alerting-aggregation/index.md) Alerts are: `Edit`, `Tick`, `Undo`, `AggChange`
- `[trigger]` values that can be returned for [Row Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) are: `Added`, `Edited`, `Deleted`, `Loaded`
**Example: Custom Alert Messages (Templates)**
Providing Custom Alert Message using Template Literals
- This demo shows how to provide a Custom Alert Message using the Alert Definition with **Template Literals**
- We have created 3 Alerts each of which provides a custom Header or Text (or both) using different Template Literal props:
- A `Warning` [Data Change Alert](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) fires any time a value is changed in the `Language` Column - with templates in both Message Header and Text
- A `Success` [Row Change Alert](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) fires when a new Row is added (can by triggered by "Add Python" button in Dashboard) - with template in Message Text
- An `Info` [Aggregation Alert](https://www.adaptabletools.com/docs/handbook-alerting-aggregation/index.md) fires when the lowest row in the `Github Watchers` column is less than 50 - with template in Message Header
```ts
import {
AdaptableButton,
AdaptableOptions,
DashboardButtonContext,
DataUpdateConfig,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export default function createPython(): WebFramework {
return {
id: Math.floor(Math.random() * (1000000 - 5000 + 1) + 200000),
name: 'python',
description: 'A very popular language.',
created_at: new Date().toDateString(),
updated_at: new Date().toDateString(),
pushed_at: new Date().toDateString(),
github_stars: 5000,
language: 'Python',
open_issues_count: 750,
license: 'MIT License',
github_watchers: 6671,
topics: ['duck typing', 'proxies', 'prerformance', 'solid'],
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 12326,
open_pr_count: 749,
closed_pr_count: 1708,
week_issue_change: 15,
};
}
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Alert Message - Templates',
notificationsOptions: {
duration: 'always',
},
dashboardOptions: {
customDashboardButtons: [
{
label: 'Add Python Row',
buttonStyle: {
tone: 'neutral',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: DashboardButtonContext
) => {
const python: WebFramework = createPython();
const dataUpdateConfig: DataUpdateConfig = {
runAsync: true,
addIndex: 0,
};
context.adaptableApi.gridApi.addGridData([python], dataUpdateConfig);
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-language',
MessageType: 'Warning',
Scope: {
ColumnIds: ['language'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
MessageHeader: '[column] Column Changed!',
MessageText:
'Value changed from [oldValue] to [newValue] in row where framework is "[rowData.name]" (Primary Key: [primaryKeyValue])',
AlertProperties: {
DisplayNotification: true,
},
},
{
Name: 'alert-row-added',
Rule: {
ObservableExpression: 'ROW_ADDED()',
},
MessageType: 'Success',
MessageHeader: 'You added a row',
MessageText: '[numberOfRows] Rows were [trigger]',
Scope: {
All: true,
},
AlertProperties: {
DisplayNotification: true,
HighlightRow: {
BackColor: 'Purple',
ForeColor: 'White',
},
},
},
{
Name: 'alert-github-watchers',
MessageType: 'Info',
Scope: {
All: true,
},
MessageHeader: '[trigger] Alert activated ',
Rule: {
AggregatedBooleanExpression: 'MIN([github_watchers] ) < 50 ',
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Alert Options
Alert Definition Template Literals are sufficient to meet most use cases where a different Message is required to appear each time the Alert is triggered.
However if greater custom flexibility is required, developers can create a completely dynamic Message with any text - via 2 function properties in [Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md):
Both functions receive Context describing the Change that triggered the Alert (and associated Alert Definition)
- `alertMessageHeader` - allows developers to provide a custom message **header**
- `alertMessageText` - allows developers to provide custom message **text**
### `alertMessageHeader`
Function providing a Header to display for an Alert
By default the header displayed in an Alert is provided by the `MessageHeader` property in the Alert Definition.
If that is not provided, AdapTable will provide the Message dynamically based on the Alert Rule and Cell Change.
However the highest priority is given to this property - a function to be invoked by AdapTable when the Alert fires.
The function receives an [`Alert Message Context`](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md) object (which includes an Alert Definition and Cell and Grid Data Change information) and returns a string:
```ts
alertMessageHeader?: (alertMessageContext: AlertMessageContext) => string | undefined;
```
The full definition of the Alert Message Context is as follows:
| Property | Type | Description |
| --- | --- | --- |
| [alertDefinition](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md#alertdefinition) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Current Alert Definition |
| [cellDataChangedInfo](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md#celldatachangedinfo) | [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md)`` | Cell Data change that might have triggered the Alert |
| [rowDataChangedInfo](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md#rowdatachangedinfo) | [`RowDataChangedInfo`](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md)`` | Row Data change that might have triggered the Alert (e.g. Row Added or Removed) |
```ts {4}
// Set a custom Alert Header for when the changed Column is Github Stars
const adaptableOptions: AdaptableOptions = {
alertOptions: {
alertMessageHeader: (alertMessageContext: AlertMessageContext) => {
if(alertMessageContext.cellDataChangedInfo.column.columnId=='github_stars'){
return 'Changed Stars!'
}
}
},
}
```
### `alertMessageText`
Function providing a Message to display in an Alert
By default the message displayed in an Alert is provided by the `MessageText` property in the Alert Definition.
If that is not provided, AdapTable will provide the Message dynamically based on the Alert Rule and Cell Change.
However the highest priority is given to this property - a function to be invoked by AdapTable when the Alert fires.
The function receives an [`Alert Message Context`](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md) object (which includes an Alert Definition and Cell and Grid Data Change information) and returns a string:
```ts
alertMessageText?: (alertMessageContext: AlertMessageContext) => string | undefined;
```
The full definition of the Alert Message Context is as follows:
| Property | Type | Description |
| --- | --- | --- |
| [alertDefinition](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md#alertdefinition) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Current Alert Definition |
| [cellDataChangedInfo](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md#celldatachangedinfo) | [`CellDataChangedInfo`](https://www.adaptabletools.com/docs/reference/celldatachangedinfo.md)`` | Cell Data change that might have triggered the Alert |
| [rowDataChangedInfo](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md#rowdatachangedinfo) | [`RowDataChangedInfo`](https://www.adaptabletools.com/docs/reference/rowdatachangedinfo.md)`` | Row Data change that might have triggered the Alert (e.g. Row Added or Removed) |
```ts {4}
// Set a custom Alert Message for when the changed Column is Github Stars
const adaptableOptions: AdaptableOptions = {
alertOptions: {
alertMessageText: (alertMessageContext: AlertMessageContext) => {
if(alertMessageContext.cellDataChangedInfo.column.columnId=='github_stars'){
return 'The stars have changed!'
}
}
},
}
```
- These 2 properties are only available for Alerts created at Design-Time and cannot be set in the UI
- This is because Alert State is saved as JSON which needs to be stringified (and cannot include functions)
**Example: Custom Alert Messages (Options)**
Providing Custom Alert Message via Alert Options
- This demo shows how to provide a Custom Message Header and Text via Alert Options - so that they are diferent each time the Alert fires:
- An `Info` Alert fires when any value is changed in the `Github Stars` column
- The Custom Header references the RowData to get the Framework in the row where the change was made
- The Custom Text references the new value that has been given to the Cell which triggered the Alert
### Expand to see the Custom Header and Text Messages provided
The Alert Definition contains the basic Alert Definition:
```ts
Alert: {
AlertDefinitions: [
{
Name: 'alert-any',
MessageType: 'Info',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
```
In Alert Options we provide Custom Message Header and Text if the change occurred in the Github Stars column
Note: we have to return undefined if its not a match so we can "fall through" to the other options
```ts
alertOptions: {
alertMessageHeader: (alertMessageContext: AlertMessageContext) => {
return alertMessageContext.cellDataChangedInfo?.column.columnId == 'github_stars' ?
'Stars changed for: ' + alertMessageContext.cellDataChangedInfo?.rowData['name']
: undefined;
},
alertMessageText: (alertMessageContext: AlertMessageContext) => {
return alertMessageContext.cellDataChangedInfo?.column.columnId == 'github_stars' ?
'New value for Github Stars is: ' + alertMessageContext?.cellDataChangedInfo?.newValue
: undefined;
},
},
```
- Edit a cell in the `Github Stars` Column and see the Alert with the custom Header and Text messages
- Note the Alert Message is different for eaach row in the Grid
```ts
import {AdaptableOptions, AlertMessageContext} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Alert Message - Options',
alertOptions: {
alertMessageHeader: (alertMessageContext: AlertMessageContext) => {
return alertMessageContext.cellDataChangedInfo?.column.columnId ==
'github_stars'
? 'Stars changed for: ' +
alertMessageContext.cellDataChangedInfo?.rowData['name']
: undefined;
},
alertMessageText: (alertMessageContext: AlertMessageContext) => {
return alertMessageContext.cellDataChangedInfo?.column.columnId ==
'github_stars'
? 'New value for Github Stars is: ' +
alertMessageContext?.cellDataChangedInfo?.newValue
: undefined;
},
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Info',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Alert Notification
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-notifications
- AdapTable Alerts can be configured to display a Notification when triggered
- The Notification can be configured to display an AdapTable Form which can be one of 2 types:
- fully defined form with a full range of controls (can include multiple inputs, buttons and other UI controls)
- reduced form with Alert Command Buttons which are wired up to System (and Custom) Alert Commands
A very common [Alert Behaviour](https://www.adaptabletools.com/docs/handbook-alerting-behaviours/index.md) is to display a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) whenever the Alert fires.
This is done by setting `DisplayNotification` to **true** in the `AlertProperties` section of the Alert Definition
By default the Notification will display the Alert's Message - the Header and Text that describe the Alert.
See [Alert Message](https://www.adaptabletools.com/docs/handbook-alerting-message/index.md) for instructions on the different ways this Message can be provided
Alternatively, the Notification can be configured, instead, to show an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md).
This Alert Form can be configured to render 2 different sets of content
- a set of **Alert Buttons** - each with an associated _Alert Command_
- a fully featured **Alert Form** (including any UI controls that are required)
## Alert Command Buttons
The Alert Notification can be configured to show a set of **Alert Command Buttons**.
Alert Command Buttons are highly-configurable [Adaptable Buttons](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md), with many properties available, e.g. for managing style, visibility, and enabled status.
If using [OpenFin](https://www.adaptabletools.com/docs/integrations-openfin/index.md) or [interop.io](https://www.adaptabletools.com/docs/integrations-interop/index.md) Plugins, these buttons will display with other Notifications shown by those containers
Each Button has an, additional, `Actions` property - which can contain an array of Alert Button Actions.
As the name implies, these actions will do something when the Button is clicked.
AdapTable will automatically wire up these Actions to the `onClick` of the Button
There are 2 types of Alert Command Buttons:
- **System** Command Buttons - shipped by AdapTable for the most common use cases (so far 7 are available)
- **Custom** Command Buttons - provided by developers to deal with bespoke requirements
- Alert Commands differ to [Alert Behaviours](https://www.adaptabletools.com/docs/handbook-alerting/index.md#alert-behaviours) as the latter trigger when the Alert itself is fired
- However Alert Commands trigger when a Button in an **Alert Form** is clicked
Alert Command Buttons can be provided by:
- developers using [Alert Initial State](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md) (via the `AlertForm` property of the [`Alert Definition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md))
- by run-time users in the `Notification` section of the Alert Wizard
Alerts created by end users at run-time can **only** contain Command Buttons (and not fully-featured Alert Forms)
### System Alert Button Actions
AdapTable provides 7 Alert Commands, selectable by end-users when creating an Alert in the AdapTable UI:
- `highlight-cell`
- `highlight-row`
- `jump-to-cell`
- `jump-to-row`
- `jump-to-column`
- `suspend`
- `undo`
The `suspend` Action essentially sets the [IsSuspended](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#suspending-objects) property in the Alert Definition to _true_
**Example: System Alert Command Buttons**
Using Alert Command Buttons
- This demo fires an Alert when any value in `Github Stars` column is changed
- It displays a Notification with 2 Buttons that are attached to System Alert Commands:
- `Show Me` - is wired up to 2 Commands: `highlight-cell` and `jump-to-cell`
- `Undo` - triggers 1 Command: `undo`
- Edit a cell in the `Github Stars` Column and see the Alert with 2 Actions. Click 'Notify' to see the System Status message which is sent
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'System Alert Action Buttons',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert', 'SystemStatus'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
AlertProperties: {
DisplayNotification: true,
},
AlertForm: {
Buttons: [
{
Label: 'Show Me',
Command: ['highlight-cell', 'jump-to-cell'],
ButtonStyle: {
tone: 'neutral',
variant: 'raised',
},
},
{
Label: 'Undo',
Command: ['undo'],
ButtonStyle: {
tone: 'info',
variant: 'outlined',
},
},
],
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Custom Alert Button Actions
In addition to the Alert Commands provided by AdapTable, developers can supply their own Commands.
This is done via the `commandHandlers` property in [Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md).
- Custom Alert Commands can then be referenced in [Alert Initial State](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md), where they can be "wired up" to Alert Buttons
- Additionally AdapTable will display them in the Notifications step in the Alert Wizard to assist run-time users
### `commandHandlers`
Custom onClick Handlers for Buttons (displayed in Alert Notifications)
[`CommandHandler[]`](https://www.adaptabletools.com/docs/reference/commandhandler.md)
Provided by developers to supplement the System Alert Commands shipped with AdapTable.
The [`CommandHandler`](https://www.adaptabletools.com/docs/reference/commandhandler.md) object contains a `name` property and a `handler` function, and is defined as follows:
```ts
export declare type CommandHandler = {
name: string;
handler: (button: AlertButton, context: AlertFormContext) => void;
};
```
As can be seen the `handler` function is identical in nature to the Alert Button's `onClick` - taking the Button and the Alert Context and returning void.
```ts {4}
commandHandlers: [
{
name: 'email-support',
handler: (
button: AdaptableButton,
context: AlertFormContext
) => {
// Send the Alert details to an Email recipient
},
},
],
```
**Example: Custom Alert Command Buttons**
Providing Custom Alert Command Buttons
- This demo fires an Alert when any value in `Github Stars` column is changed.
- The Alert displays a Notification with a `Notify` Button which is attached to a Custom (i.e. bespoke) Alert Command `email-support`
- Note: for this impelementation we simply send a [System Status Message](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) but a real world implementation would be different
- Edit a cell in the `Github Stars` Column and see the Alert with the 'Notify' Button
- Click the Button to see the System Status message which is sent
```ts
import {
AdaptableOptions,
AlertButton,
AlertFormContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Alert Action Buttons',
alertOptions: {
commandHandlers: [
{
name: 'email-support',
handler: (
button: AlertButton,
context: AlertFormContext
) => {
// Normally would email support, here just send System Status Message
context.adaptableApi.systemStatusApi.setWarningSystemStatus(
context.alert.header,
context.alert.message
);
},
},
],
},
notificationsOptions: {
duration: 'always',
position: 'BottomCenter',
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert', 'SystemStatus'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert', 'SystemStatus'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
AlertProperties: {
DisplayNotification: true,
},
AlertForm: {
Buttons: [
{
Label: 'Notify',
Command: ['email-support'],
ButtonStyle: {
tone: 'info',
variant: 'text',
},
},
],
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Alert Forms
The Alert Notification can be configured, instead, to render a full **Alert Form**.
This is a fully-featured, UI-rich [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md), containing multiple inputs and controls (with validation).
An Alert Form can only be configured by developers at design-time, and requires a 2-step process:
1. The Form is configured in full in the `alertForms` section of [Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
2. The Form is referenced by name in the `AlertForm` property of the [`Alert Definition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) in [Alert Initial State](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
The [Adaptable Form Guide](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) has full instructions on configuring dynamic Forms with multiple inputs and validation
### `alertForms`
Fully configured Forms to show in Alert Notifications
[`AlertForm[]`](https://www.adaptabletools.com/docs/reference/alertform.md)
Alert Notifications can contain [Adaptable Forms](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) with multiple inputs and buttons.
```ts {1}
alertForms: [
{
name: 'setStars',
form: {
fields: [
{
fieldType: 'number',
label: 'Stars',
name: 'github_stars',
},
],
buttons: [
{
label: 'Set',
disabled: (_button, context) => {
if (!context.formData?.github_stars) {
return true;
}
const value = Number(context.formData?.github_stars);
return value <= 0 || isNaN(value);
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert = context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: cellChangedInfo.column.columnId,
newValue: Number(context.formData?.github_stars),
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
{
label: 'Cancel',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert = context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: cellChangedInfo?.oldValue,
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
],
},
},
],
```
**Example: Adaptable Forms in Alerts**
Alerts can display an Adaptable Form when triggered
- This demo displays an Alert Form when a cell in `Github Stars` column is given a negative value
- The Form contains 3 elements:
- a numeric input which will receive the new value for the Cell
- a `Set` button - which will replace the 0 in the Cell with the value provided in the input
- a `Cancel` Button - which will revert the Cell to its initial value
- Set a `GitHub Stars` cell to a negative value and see the Alert Form appear with the input and the 2 buttons
- Provide a new value and click 'Set' and note how the cell updates
- Click 'Cancel' and note how the cell reverts to the initial value
```ts
import {
AdaptableCellChangedAlert,
AdaptableOptions,
CellDataChangedInfo,
CellUpdateRequest,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Alert Form',
notificationsOptions: {
// this can be a number (duration in millis) or the string 'always'
duration: 'always',
},
alertOptions: {
alertForms: [
{
name: 'setStars',
form: {
fields: [
{
fieldType: 'number',
label: 'Stars',
name: 'github_stars',
},
],
buttons: [
{
label: 'Set',
disabled: (_button, context) => {
if (!context.formData?.github_stars) {
return true;
}
const value = Number(context.formData?.github_stars);
return value <= 0 || isNaN(value);
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert =
context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: cellChangedInfo.column.columnId,
newValue: Number(context.formData?.github_stars),
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
{
label: 'Cancel',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (_button, context) => {
if (context.alert.alertType == 'cellChanged') {
const cellChangedAlert: AdaptableCellChangedAlert =
context.alert as AdaptableCellChangedAlert;
const cellChangedInfo = cellChangedAlert.cellDataChangedInfo;
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'github_stars',
newValue: cellChangedInfo?.oldValue,
primaryKeyValue: cellChangedInfo?.primaryKeyValue,
rowNode: cellChangedInfo?.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
},
},
],
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Warning',
MessageHeader: 'Github Stars Cannot be Negative',
MessageText:
'Provide a new value for Github Stars, or click "Cancel" to undo',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'Negative',
},
],
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
AlertForm: 'setStars',
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Observable Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-observables
- Observable Alerts fire when an observed event happens to grid data
- There are 3 types of changes which can be observed;
- Row Changes
- Grid Changes
- No Changes
- Observable Alerts leverage AdapTable Rx which can be set to watch for particular changes or behaviour in AG Grid
Alerts can be fired using [Observable Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md) which watch for changes (or lack of changes).
These are advanced, reactive-type Expressions, which are triggered by [Adaptable Rx](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md#reactive-expressions).
There are 5 main elements to an Observable Expression:
- **Scope** - either a particular **Row** (or set of Rows) or the entire **Grid**
- **Observable Type** - can be `ROW_CHANGE`, `GRID_CHANGE`, `ROW_ADDED` or `ROW_REMOVED`
- **Change Type** - can be - `MIN`, `MAX`, `COUNT` or `NONE`
- **Duration** - how long should the change be observed
- **WHERE Clause** - limits the change only to rows that match the expression
The [AdapTableQL Guide](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) provides full details on writing [Observable Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md)
For instance we can set an Alert to fire in each of these use cases:
- a particular row has not changed in the last hour
- a given row has changed 5 times in 10 minutes
- a column / cell value is the highest that its been all day
- there have been no changes in the Grid for 2 hours
- a new row has been added to the Grid
- 3 rows have been removed from the Grid in the last 4 hours
Observable Expressions require the Alert to have a [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of `All` (i.e. the whole row)
## Row Changes
The most common use case for Observable Alerts is to see if a particular change has happened in each row.
A row change Observable Alert will watch each (relevant) row in the Grid and fire if needed.
**Example: Alerts: Observing Row Changes**
Observable Alerts fired on Row Changes
- This demo showcases 2 Alerts which are triggered by Observable **Row Change** Expressions:
- If *Github Stars* in any Row changes `3 times` within a `2 minute` timeframe
- When *Open Issues* count in a Row is the highest value it has been within the last hour - for rows where the `language` is `JavaScript`
- Click the *Add Star* [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) button next to `Github Stars`; once it is clicked 3 times in a row, the Info Alert will be triggered
- Click the *Open an Issue* [Action Column](https://www.adaptabletools.com/docs/handbook-action-column/index.md) button next to `Open Issues` Column - if the row matches the `WHERE` clause, it will trigger the Success Alert
```ts
import {
ActionColumnButton,
ActionColumnContext,
AdaptableApi,
AdaptableButton,
AdaptableOptions,
CellUpdateRequest,
} from '@adaptabletools/adaptable';
export function incrementCellValue(
columnName: string,
context: ActionColumnContext,
amount: number = 1
): void {
const currentItemCount = context.rowNode.data[columnName];
const cellUpdateRequest: CellUpdateRequest = {
columnId: columnName,
newValue: currentItemCount + amount,
primaryKeyValue: context.primaryKeyValue,
rowNode: context.rowNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
}
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Observable Alerts Row Changes',
adaptableStateKey: `${Date.now()}`,
actionColumnOptions: {
actionColumns: [
{
columnId: 'increaseStars',
friendlyName: 'Add Star',
actionColumnButton: {
label: '+',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (
_button: ActionColumnButton,
context: ActionColumnContext
) => {
incrementCellValue('github_stars', context);
},
},
},
{
columnId: 'openIssue',
friendlyName: 'Open an Issue',
actionColumnButton: {
label: '+',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (
_button: ActionColumnButton,
context: ActionColumnContext
) => {
incrementCellValue('open_issues_count', context);
},
},
},
{
columnId: 'closeIssue',
friendlyName: 'Close an Issue',
actionColumnButton: {
label: '-',
buttonStyle: {
tone: 'neutral',
variant: 'raised',
},
onClick: (
_button: ActionColumnButton,
context: ActionColumnContext
) => {
incrementCellValue('open_issues_count', context, -1);
},
},
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'increaseStars',
'license',
'openIssue',
'open_issues_count',
'closeIssue',
],
},
],
},
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Alert: {
AlertDefinitions: [
{
Name: 'alert-observable-github-stars-change',
MessageType: 'Info',
MessageHeader: "That's 3 Changes!",
MessageText: 'Github Stars Changed 3 times in this Row',
Scope: {All: true},
Rule: {
ObservableExpression:
"ROW_CHANGE(COUNT([github_stars],3) ,TIMEFRAME('2m'))",
},
AlertProperties: {
DisplayNotification: true,
},
},
{
Name: 'alert-observable-open-issues-count-change',
MessageType: 'Success',
Scope: {All: true},
Rule: {
ObservableExpression:
"ROW_CHANGE( MAX([open_issues_count] ), TIMEFRAME('1h')) WHERE [language] = 'JavaScript'",
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
},
};
```
## Grid Changes
Another common use case for Observable Alerts is for any change in the Grid.
This is useful if you want to be alerted about all behaviour in the Grid rather than particular rows.
**Example: Alerts: Observing Grid Changes**
Observable Alerts fired on Grid Changes
- This example contains 2 Alerts which are triggered by Observable **Grid Change** Expressions:
- If `Language` Column in the Grid changes *3 times* within a *5 minute* timeframe
- If `Github Stars` Column in the Grid changes *2 times* within a *1 minute* timeframe - but only for rows where `License` is 'MIT License'
```ts
import {ActionColumnContext, AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Observable Alert Grid Changes',
adaptableStateKey: `${Date.now()}`,
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'license',
'open_issues_count',
],
},
],
},
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Alert: {
AlertDefinitions: [
{
Name: 'alert-observable-language-change',
MessageType: 'Error',
Scope: {All: true},
Rule: {
ObservableExpression:
"GRID_CHANGE(COUNT([language], 3), TIMEFRAME('5m') ) ",
},
AlertProperties: {
DisplayNotification: true,
},
},
{
Name: 'alert-observable-github-stars-change',
MessageType: 'Info',
Scope: {All: true},
Rule: {
ObservableExpression:
"GRID_CHANGE(COUNT([github_stars], 2), TIMEFRAME('1m') ) WHERE [license] = 'MIT License'",
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
},
};
```
## No Changes
Another use case for Observable Alerts is to watch for **no changes** in the data.
This is particularly useful if you have ticking data or you expect some changes at some point
AdapTable can observe for No Change on either a [per-Row](#row-changes) or a [per-Grid](#grid-changes) basis.
**Example: Alerts: Observing No Changes**
Observable Alerts fired on No Changes
- This demo contains an Alert which is triggered by Observable Expressions watching for **No Changes**
- The Alert triggers if the *Github Stars* Column in the Grid is not updated within a `5 second` timeframe
- We have subscribed to the [Alert Fired Event](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md) and we set [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) for the *Github Stars* Column
- Click the "Turn Off Ticking Data" button and wait for 5 seconds and note the Alert will fire
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
import {turnOffTickingData} from 'tickingDataHelper';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Observable Alert No Changes',
dashboardOptions: {
customToolbars: [
{
name: 'tickingToolbar',
title: 'Ticking',
toolbarButtons: [
{
label: 'Turn off Ticking Data',
onClick: () => {
turnOffTickingData();
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
],
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert', 'tickingToolbar', 'SystemStatus'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert', 'SystemStatus'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-observable-github-stars-no-change',
MessageType: 'Warning',
MessageHeader: 'Stale Data!',
MessageText: 'No Changes in Github Stars in last 5 seconds',
Scope: {All: true},
Rule: {
ObservableExpression:
"GRID_CHANGE(NONE([github_stars]) , TIMEFRAME('5s')) ",
},
AlertProperties: {
DisplayNotification: true,
},
},
],
},
FlashingCell: {
FlashingCellDefinitions: [
{
Name: 'flashingCell-numeric-anyChange',
Scope: {
DataTypes: ['number'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'github_stars',
'license',
'github_watchers',
'language',
'open_issues_count',
'closed_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'description',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo, FormatColumn} from '@adaptabletools/adaptable';
import {tickNumericData} from 'tickingDataHelper';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
tickNumericData(adaptableApi, 1000, ['github_stars']);
adaptableApi.eventApi.on('AlertFired', event => {
const formatColumn: FormatColumn = {
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
Style: {
BackColor: 'Red',
ForeColor: 'White',
},
};
adaptableApi.formatColumnApi.addFormatColumn(formatColumn);
adaptableApi.systemStatusApi.setErrorSystemStatus('No Ticking Data!');
});
};
```
## Row Added / Removed
Observable Alerts can also be used to monitor when Rows have been added or removed from the Grid.
This is done using the `ROW_ADDED` and `ROW_REMOVED` Observable Expression keywords.
See [Row Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-row-change/index.md) for more details and accompanying demos
## Suspending Alerts
When an Observable Alert is suspended, the subscription is **removed**, and will be re-created when unsuspended.
- This means that any changes in the data during the Alert's suspension are **not** observed
- The count / watch starts again from scratch when the Alert is unuspended
---
# Relative Change Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-relative-change
- Relative Change Alerts evaluate based on the nature of the data change in a Cell’s value
- They can respond to any change, a relative change or an absolute change
Relative Change Alerts are similar to [Data Change Alerts](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md), but they evaluate on the **relative nature** of the change made to a given Cell's value.
There are 3 Relative Change Alerts types, each levaraging an associated [Relative Change Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md):
| Function | When Alert is Triggered |
| --------------- | ----------------------------------------------------------- |
| ANY_CHANGE | **Any** change at all to the Cell's value |
| PERCENT_CHANGE | If the value of Cell changes by a given **percent** amount |
| ABSOLUTE_CHANGE | If the value of Cell changes by a given **absolute** amount |
See [Relative Change Expressions in AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md) for more details
## Any Change
Any *Any Change* Alert fires if there is **any** change at all to the Cell's value.
It leverages the `ANY_CHANGE` [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md).
**Example: Alerts: Relative Any Change**
Alerts fired due to Any Change
- This example displays an *Info* Alert which fires when there is **any change** to a Cell's value in any numeric column (using `ANY_CHANGE` expression)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Relative Any Change Alert',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-info-name-change',
MessageType: 'Info',
Scope: {
DataTypes: ['number'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE([name])',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Percent Change
A *Percent Change* Alert fires if the value of a Cell changes by a given **percent** amount.
It leverages the `PERCENT_CHANGE` [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md).
`PERCENT_CHANGE` can be given a "direction" to limit the evaluation to percent increases or decreases
**Example: Alerts: Relative Percent Change**
Alerts fired due to a Percent Change
- This example displays 2 *Warning* Alerts which check for relative percent changes (leveraging the `PERCENT_CHANGE` expression function)
- on the `Github Stars` column if the cell's value changes by more than 50% (in any direction)
- on the `Github Watchers` column if the cell's value **increases** by more than 50%
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Relative Percent Change Alert',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-warning-github-stars',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'PERCENT_CHANGE([github_stars]) > 50',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
{
Name: 'alert-warning-github-watchers',
MessageType: 'Warning',
Scope: {
ColumnIds: ['github_watchers'],
},
Rule: {
BooleanExpression:
'PERCENT_CHANGE([github_watchers], "INCREASE") > 50',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'github_watchers',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Absolute Change
An *Absolute Change* Alert fires if the value of a Cell changes by a given **absolute** amount.
It leverages the `ABSOLUTE_CHANGE` [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-relative-change/index.md).
`ABSOLUTE_CHANGE` can be given a "direction" to limit the evaluation to percent increases or decreases
**Example: Alerts: Relative Absolute Change**
Alerts fired due to an Absolute Change
- This example displays 2 *Success* Alerts which check for relative absolute changes (leveraging the `ABSOLUTE_CHANGE` expression function)
- on the `Github Stars` column if the cell's value changes by more than 100 (in any direction)
- on the `Github Watchers` column if the cell's value **decreases** by exactly 20
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Relative Absolute Change Alert',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-info-name-change',
MessageType: 'Info',
Scope: {
ColumnIds: ['name'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE([name])',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
{
Name: 'alert-warning-open-issues-count',
MessageType: 'Warning',
Scope: {
ColumnIds: ['open_issues_count'],
},
Rule: {
BooleanExpression: 'PERCENT_CHANGE([open_issues_count]) > 50',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
{
Name: 'alert-warning-closed-issues-count',
MessageType: 'Warning',
Scope: {
ColumnIds: ['closed_issues_count'],
},
Rule: {
BooleanExpression:
'PERCENT_CHANGE([closed_issues_count], "INCREASE") > 50',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
{
Name: 'alert-success-github-stars',
MessageType: 'Success',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
BooleanExpression: 'ABSOLUTE_CHANGE([github_stars]) > 100',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
{
Name: 'alert-success-github-watchers',
MessageType: 'Success',
Scope: {
ColumnIds: ['github_watchers'],
},
Rule: {
BooleanExpression:
'ABSOLUTE_CHANGE([github_watchers], "DECREASE") = 20',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'github_watchers',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Row Change Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-row-change
- Row Change Alerts are Alerts which can be fired when the Rows in the Grid change
- This can be either when:
- a new Row is added to AG Grid
- an existing Row is deleted from AG Grid
AdapTable offers 2 Alerts which fire in response to changes in the number of rows in AG Grid's data source:
- `ROW_ADDED` - wraps the [ROW_ADDED](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md#row_added) Observable Expression Function
- `ROW_REMOVED` - wraps the [ROW_REMOVED](https://www.adaptabletools.com/docs/adaptable-ql-expression-observable/index.md#row_added) Observable Expression Function
These are both specialised types of [Observable Alert](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md) which look for changes in the Grid or given rows
When defining the Alert in Initial State, the [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) in the Alert Definition should be set to `All`
## Added Row Alert
The `ROW_ADDED` Expression can be used to create an Observable Alert which will fire each time a new row is added to AG Grid.
- If adding the new row programmatically, use [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)'s' `addGridData` function (see [Managing Row Data](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md#managing-row-data) for more info)
- **Don't** directly use `applyTransaction` (or `applyTransactionAsync`) in AG Grid's API as it bypasses new row detection
**Example: Alerts: Row Added**
Alerts on Rows being Added to AdapTable
- This demo has a `ROW_ADDED` Alert which fires when a now row is added to the Grid
- We added a `Highlight Row` Behaviour to easily see which Row was added
- The new Row can be added to the Grid in 2 ways:
- Clicking a Custom Dashboard button that then invokes the `addGridData` method in [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md)
- Providing an [Action Column Command button](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md) of `create` which opens the [Create Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md)
- You can mimic adding a new Row in one of 2 ways - both of which will trigger the Alert:
- Click the `Add Python Row` [Dashboard Button](https://www.adaptabletools.com/docs/ui-dashboard-buttons/index.md)
- Click the `Create` Button (which automatically displays an empty Row Form allowing you easily to add the new Row)
```ts
import {
AdaptableButton,
AdaptableColumn,
AdaptableOptions,
DashboardButtonContext,
DataUpdateConfig,
RowFormColumnContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export default function createPython(): WebFramework {
return {
id: Math.floor(Math.random() * (1000000 - 5000 + 1) + 200000),
name: 'python',
description: 'A very popular language.',
created_at: new Date().toDateString(),
updated_at: new Date().toDateString(),
pushed_at: new Date().toDateString(),
github_stars: 5000,
language: 'Python',
open_issues_count: 750,
license: 'MIT License',
github_watchers: 6671,
topics: ['duck typing', 'proxies', 'prerformance', 'solid'],
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 12326,
open_pr_count: 749,
closed_pr_count: 1708,
week_issue_change: 15,
};
}
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Row Added Alert',
actionColumnOptions: {
actionColumns: [
{
columnId: 'action',
friendlyName: 'Actions',
actionColumnButton: [
{
command: 'create',
},
],
},
],
},
rowFormOptions: {
setPrimaryKeyValue: context => {
return {
...context.rowData,
id: context.adaptableApi.gridApi.getRowCount() + 1,
};
},
includeColumnInRowForm: (rowFormColumnContext: RowFormColumnContext) => {
const column: AdaptableColumn = rowFormColumnContext.adaptableColumn;
return column.columnTypes?.includes('actionColumn') ||
column.columnId == 'id'
? false
: true;
},
},
dashboardOptions: {
customDashboardButtons: [
{
label: 'Add Python Row',
buttonStyle: {
tone: 'neutral',
variant: 'outlined',
},
onClick: (
_button: AdaptableButton,
context: DashboardButtonContext
) => {
const python: WebFramework = createPython();
const dataUpdateConfig: DataUpdateConfig = {
runAsync: true,
addIndex: 0,
};
context.adaptableApi.gridApi.addGridData([python], dataUpdateConfig);
},
},
],
},
notificationsOptions: {
position: 'TopCenter',
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-row-added',
Rule: {
ObservableExpression: 'ROW_ADDED()',
},
MessageType: 'Success',
MessageHeader: 'You added a row',
MessageText: 'Hey! A row was added',
Scope: {
All: true,
},
AlertProperties: {
DisplayNotification: true,
HighlightRow: {
BackColor: 'Purple',
ForeColor: 'White',
},
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'action',
'name',
'language',
'github_stars',
'license',
'created_at',
'has_wiki',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Added Row Conditional Alert
Because `ROW_ADDED` is an Observable Alert, it can be provided with an additional `WHERE` clause.
This specifies when the Alert should fire (ie. what extra requirement is available)
- If creating a Conditional Row Changed Alert in the UI, you will need to select the, fuller, Observable Alert option
- This option contains a stop that renders the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md) which is where the `WHERE` clause can be added
**Example: Alerts: Row Added with WHERE**
Observable Alerts fired when Row Added with WHERE clause
- This demo contains an Add Row Warning Alert but the Rule has a `WHERE` clause in the Expression, specifying the Alert should only fire when the new Row:
- has a `Language` of *TypeScript*
- and `Has Wiki` is *true*
- We have added a [Dashboard Button](https://www.adaptabletools.com/docs/ui-dashboard-buttons/index.md) which opens an [Add Row Form](https://www.adaptabletools.com/docs/handbook-row-form/index.md) to enable the new row to be added
- Click the 'Add New Row' Button in the Dashboard to open an Add Row Form
- Provide any `Name`, select 'TypeScript' for `Lanugage` and check `Has Wiki` and click Save
- The new Row will be added to the Grid and the Alert will fire
```ts
import {
AdaptableButton,
AdaptableOptions,
DashboardButtonContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Row Added Alert with WHERE',
adaptableStateKey: `${Date.now()}`,
editOptions: {
showSelectCellEditor: context => {
return context.column.columnId === 'language';
},
},
rowFormOptions: {
setPrimaryKeyValue: context => {
return {
...context.rowData,
id: context.adaptableApi.gridApi.getRowCount() + 1,
};
},
},
dashboardOptions: {
customDashboardButtons: [
{
label: 'Add New Row',
onClick: (
button: AdaptableButton,
context: DashboardButtonContext
) => {
context.adaptableApi.rowFormApi.displayCreateRowForm();
},
buttonStyle: {
variant: 'raised',
tone: 'info',
},
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: ['name', 'language', 'license', 'has_wiki'],
},
],
},
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Alert: {
AlertDefinitions: [
{
Name: 'alert-row-added-where-language',
MessageType: 'Warning',
Scope: {All: true},
Rule: {
ObservableExpression:
"ROW_ADDED() WHERE [language] = 'TypeScript' AND [has_wiki] = TRUE ",
},
AlertProperties: {
DisplayNotification: true,
HighlightRow: {
BackColor: 'White',
ForeColor: 'Black',
},
},
},
],
},
},
};
```
## Removed Row Alert
Another commonly used Observable Alert requirement is row removal, ie. to fire an Alert when rows have been from the Grid.
The `ROW_REMOVED` Expression can be used to create an Observable Alert which will fire each time a Row is removed from AG Grid.
**Example: Alerts: Row Removed**
Alerts on Rows being Removed from AdapTable
- This example fires a `ROW_REMOVED` [Observable Alert](https://www.adaptabletools.com/docs/handbook-alerting-observables/index.md) when a row is deleted (which we do via an [Action Column Command](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md) `delete` button)
- We provided a custom message for the Alert Notification via the `alertMessageText` property in [Alert Options](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md)
- Click the 'delete' [Action Column Command button](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md) and note the Row is deleted and an Alert is fired
```ts
import {AdaptableOptions, AlertMessageContext} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Row Deleted Alert',
notificationsOptions: {
position: 'BottomCenter',
},
actionColumnOptions: {
actionColumns: [
{
columnId: 'action',
friendlyName: 'Delete',
actionColumnButton: {
command: 'delete',
},
},
],
},
alertOptions: {
alertMessageText: (alertMessageContext: AlertMessageContext) => {
if (
alertMessageContext.rowDataChangedInfo &&
alertMessageContext.rowDataChangedInfo.rowTrigger == 'Delete'
) {
const deletedRow = alertMessageContext.rowDataChangedInfo.dataRows[0];
if (deletedRow) {
return 'You deleted: ' + deletedRow.name;
}
}
return undefined;
},
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-row-deleted',
Rule: {
ObservableExpression: 'ROW_REMOVED()',
},
AlertProperties: {
DisplayNotification: true,
},
MessageType: 'Info',
Scope: {
All: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'created_at',
'has_wiki',
'updated_at',
'topics',
'action',
],
ColumnPinning: {
action: 'right',
},
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Scheduled Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-schedule
- Scheduled Alerts fire at a date and time you configure
- The Schedule can be either a one off, or on a recurring cron
- Schedules are defined as specialised Scheduled Alert Definitions with a `Schedule` instead of a Rule
Scheduled Alerts notify users when a **schedule** fires.
Unlike the other AdapTable Alert types, they do not watch grid data, rules, or cell changes.
- Scheduled Alerts are ideal to use as reminders or operational prompts
- e.g. to prompt users to run an end-of-day report or review a dashboard at the same time each weekday
Scheduled Alerts use a [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) model which can be configured in 2 ways (same as [scheduled reports](https://www.adaptabletools.com/docs/handbook-exporting-scheduling/index.md)):
- **Recurring** — a `CronExpression` using a 5-field cron (e.g. `30 17 * * 1-5` for 17:30 on weekdays)
- **One-off** — a single run at a specified ISO datetime
- After a one-off Alert fires, it is **not** auto-suspended
- You can edit the `RunAt` property to run the Alert again, or suspend/delete the definition in the Alert UI
You can configure a Scheduled Alert to behave like any other Alert, including:
- displaying a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md)
- updating the Alert UI controls: Toolbar, Tool Panel and Status Bar Panel
- logging to the console
- displaying a System Status message
- Some of the behaviour available in other Alerts are not relevant to Scheduled Alerts (and are hidden in the UI)
- For instance behaviours relating to highlighting or jumping to Cells or undoing a Cell edits are removed
**Example: Alerts: Scheduled**
Creating Scheduled Alerts that run at a given time
- This example provides two Scheduled Alert definitions in Alert Initial State:
- **Daily stand-up reminder** — recurring cron (`0 9 * * *`) so the Alert runs **every day at 09:00**
- **One-off demo Alert** — runs once about **2 minutes after** the demo loads (`RunAt` is computed when the sandpack starts)
- Wait ~2 minutes after load for the one-off toast (or check **System Status** / Alert panel)
- Edit the daily alert’s cron (e.g. change hour/minute) or suspend the one-off before it fires
```ts
import { AdaptableOptions } from '@adaptabletools/adaptable';
import { WebFramework } from 'rowData';
/** One-off fires ~2 minutes after the demo loads (computed when this module runs). */
const oneOffRunAt = new Date(Date.now() + 2 * 60 * 1000).toISOString();
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Scheduled Alert',
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: { CurrentTheme: 'dark' },
Alert: {
AlertDefinitions: [
{
Name: 'Daily stand-up reminder',
MessageHeader: 'Daily stand-up',
MessageText: 'Review the grid and confirm today’s priorities.',
MessageType: 'Info',
AlertProperties: {
DisplayNotification: true,
DisplaySystemStatusMessage: true,
},
Schedule: {
IsOneOff: false,
// Every day at 09:00 (minute hour day-of-month month day-of-week)
CronExpression: '0 9 * * *',
},
},
{
Name: 'One-off demo alert',
MessageHeader: 'Scheduled alert fired',
MessageText: 'This one-off alert was set to run about 2 minutes after the demo loaded.',
MessageType: 'Success',
AlertProperties: {
DisplayNotification: true,
DisplaySystemStatusMessage: true,
IncludeSuspendButton: true,
},
Schedule: {
IsOneOff: true,
RunAt: oneOffRunAt,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'action',
'name',
'language',
'github_stars',
'license',
'created_at',
'has_wiki',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Configuring Scheduled Alerts
Scheduled Alerts are defined, and persisted, in the Alert section of Adaptable State.
### Anatomy of a Scheduled Alert
A Scheduled Alert is an object of type [`ScheduledAlertDefinition`](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md).
This is a specialised [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) containing a `Schedule` property (instead of `Rule` or `Scope`).
It inherits from [`Alert Definition Base`](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md) which is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [MessageHeader](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#messageheader) | `string` | Title of displayed Alert Message |
| [MessageText](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#messagetext) | `string` | Title of displayed Alert Message; if null, AdapTable creates dynamically using Rule & Scope |
| [MessageType](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#messagetype) | [`AdaptableMessageType`](https://www.adaptabletools.com/docs/reference/adaptablemessagetype.md) | Type of Alert: 'Info', 'Success', 'Warning', 'Error'; influences Alert colour, icon and logging |
| [Name](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#name) | `string` | Name of the Alert Definition |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
| [IsSuspended](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object |
And it contains this extra schedule-related props:
| Property | Type | Description |
| --- | --- | --- |
| [AlertProperties](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#alertproperties) | [`ScheduledAlertProperties`](https://www.adaptabletools.com/docs/reference/scheduledalertproperties.md) | Notification properties for scheduled alerts (no grid behaviours) |
| [Schedule](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#schedule) | [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) | When the alert should run |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
| [IsSuspended](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object |
The timing object is the shared [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) type:
| Property | Type | Description |
| --- | --- | --- |
| [CronExpression](https://www.adaptabletools.com/docs/reference/schedule.md#cronexpression) | `string` | Standard 5-field cron (minute hour day-of-month month day-of-week); e.g. weekdays at 09:30 → `30 9 * * 1-5` |
| [IsOneOff](https://www.adaptabletools.com/docs/reference/schedule.md#isoneoff) | `boolean` | If true, the schedule runs once (using RunAt) |
| [RunAt](https://www.adaptabletools.com/docs/reference/schedule.md#runat) | `string` | ISO datetime for a one-off run (local time); set when IsOneOff is true |
It contains an `AlertProperties` object of type [`ScheduledAlertProperties`](https://www.adaptabletools.com/docs/reference/scheduledalertproperties.md) which derives from [`Alert Presentation Properties`](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md) and defines some optional behaviour for the Alert:
| Property | Type | Description |
| --- | --- | --- |
| [DisplayNotification](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#displaynotification) | `boolean` | Displays a notification when Alert is triggered |
| [DisplaySystemStatusMessage](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#displaysystemstatusmessage) | `boolean` | Shows the alert message in the System Status panel |
| [LogToConsole](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#logtoconsole) | `boolean` | Logs the Alert message to the console |
| [NotificationDuration](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#notificationduration) | [`NotificationsOptions`](https://www.adaptabletools.com/docs/reference/notificationsoptions.md)`['duration']` | Notifiction duration(defaults to `NotificationOptions.duration`) |
| [ShowInDiv](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#showindiv) | `boolean` | Shows Alert text in the div specificed in `alertContainer` property of Container Options |
With these added properties:
| Property | Type | Description |
| --- | --- | --- |
| [IncludeSuspendButton](https://www.adaptabletools.com/docs/reference/scheduledalertproperties.md#includesuspendbutton) | `boolean` | When true, the scheduled notification includes a Suspend button |
### Providing Scheduled Alerts in Initial State
Shared Alert Definitions are Alers which must include `Schedule` (instead of `Rule` / `Scope`).
Scheduled Alerts live alongside rule-based Alerts in the same array. AdapTable distinguishes them by the presence of `Schedule`.
- `Name` — unique Alert name
- `MessageHeader` / `MessageText` — shown when the Alert fires (required for Scheduled Alerts in the UI)
- `MessageType` — `Info`, `Success`, `Warning`, or `Error` (controls colour and icon)
- `AlertProperties.DisplayNotification` — whether to show a toast when the schedule fires
- `AlertProperties.IncludeSuspendButton` — when true, the notification includes OK and Suspend buttons (otherwise OK only)
Set `Schedule.IsOneOff` to `false` and provide `CronExpression`.
Example: `30 17 * * 1-5` runs at **17:30 on weekdays**.
Set `Schedule.IsOneOff` to `true` and `RunAt` to an ISO datetime (local time).
```ts [[1, 2, "Alert"], [1, 3, "AlertDefinitions"], [2, 5, "Name"], [2, 6, "MessageHeader"], [2, 7, "MessageText"], [2, 8, "MessageType"], [2, 9, "AlertProperties"], [2, 10, "DisplayNotification"], [3, 13, "Schedule"], [3, 14, "IsOneOff"], [3, 15, "CronExpression"], [2, 19, "Name"], [2, 20, "MessageHeader"], [2, 21, "MessageText"], [2, 22, "MessageType"], [2, 23, "AlertProperties"], [2, 24, "DisplayNotification"], [4, 26, "Schedule"], [4, 27, "IsOneOff"], [4, 28, "RunAt"]]
const initialState: InitialState = {
Alert: {
AlertDefinitions: [
{
Name: 'End of day reminder',
MessageHeader: "Run 'End of Day' report",
MessageText: 'Send the report to Middle Office',
MessageType: 'Warning',
AlertProperties: {
DisplayNotification: true,
DisplaySystemStatusMessage: true,
},
Schedule: {
IsOneOff: false,
CronExpression: '30 17 * * 1-5',
},
},
{
Name: 'One-off check',
MessageHeader: 'Review figures',
MessageText: 'Please confirm today’s numbers before close',
MessageType: 'Info',
AlertProperties: {
DisplayNotification: true,
},
Schedule: {
IsOneOff: true,
RunAt: '2026-05-19T17:30:00.000Z',
},
},
],
},
};
```
For a one-off Alert / reminder at design time that fires soon after the grid loads (e.g. in a demo), compute `RunAt` dynamically (as we do in the demo above)
## Managing Scheduled Alerts
You can view active (and suspended) Scheduled Alerts in the Alert settings section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md).
Options include:
- **Create** or **Edit** a Scheduled Alert using the Alert Wizard (set message, schedule and behaviour)
- **Suspend** / **Unsuspend** — pauses scheduling without deleting the definition (`IsSuspended`)
- **Delete** — removes the Alert Definition and cancels its timers
### Creating a Scheduled Alert in the Alert Wizard
**Settings** tab:
- Enter a **Name** (must be unique among all Alert definitions).
**Alert Type** tab:
- Select **Scheduled** — “fires at a date and time you choose”.
- Other Alert types (Data Change, Validation, Observable, etc.) are hidden for the rest of the wizard.
Configure **when** the Alert runs (same builder as report schedules):
- **Recurring** — choose a preset (e.g. Every Day, Weekdays, Selected Days, Monthly) or **Custom** cron; set hour and minute.
- **One-off** — pick the date and time for a single run (`RunAt`).
AdapTable stores either `CronExpression` or `RunAt` on the alert’s `Schedule` object.
**Message Type** — choose `Info`, `Success`, `Warning`, or `Error` (colour and icon in notifications and Alert panels).
**Message Text** — for Scheduled Alerts, both fields are required:
- **Header** — title shown in the notification and Alert UI.
- **Message** — body text shown when the schedule fires.
- Check **Display a Notification when the Schedule is triggered** to show a [Toast Notification](https://www.adaptabletools.com/docs/ui-tutorial-using-toast-notifications/index.md) when the schedule runs.
- With notifications enabled, use **Alert Preview** to see the header, message, and buttons.
- The default notification includes **OK** only; enable **Include Suspend button** (or set `AlertProperties.IncludeSuspendButton`) to add a **Suspend** button on the popup.
If notifications are off, the Alert can still appear in Alert panels and system status depending on **Behaviour**.
Scheduled Alerts offer a reduced behaviour set (no cell/row highlights or jump-to, because nothing changed in the grid):
- **Show in separate `` element** — render in a dedicated Alert region if configured in your layout.
- **Log To Console** — write to the browser console when fired.
- **Show as System Status Message** — add an entry to the [System Status](https://www.adaptabletools.com/docs/handbook-system-status) panel.
If [Object Tags](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#object-tags) are enabled, assign tags so the Alert is limited to specific layouts like other Adaptable Objects.
Review all steps, then use **Finish** to save. The Alert is added to `Alert.AlertDefinitions` and timers are scheduled automatically.
---
# Alerts Technical Reference
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-technical-reference
- Alerts are configured i the Alert section of Adaptable State
- Alert Options contains many properties to enable fine-tuned configuring of Alerts
- Run-time access to Alerts is primarily available through Alert API
- The Alert Fired event is published every time an Alert is fired in AdapTable
--------------
## Alert State
The Alert section of Adaptable State contains a collection of `AlertDefinition` objects:
| Property | Type | Description |
| --- | --- | --- |
| [AlertDefinitions](https://www.adaptabletools.com/docs/reference/alertstate.md#alertdefinitions) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md)`[]` | Alert Definitions - will trigger Alerts when rule is met |
Each [`Alert Definition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) can be one of two types:
- RuleBasedAlertDefinition
- ScheduledAlertDefinition
### Base Properties
Both inherit from [`Alert Definition Base`](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md) which is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [MessageHeader](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#messageheader) | `string` | Title of displayed Alert Message |
| [MessageText](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#messagetext) | `string` | Title of displayed Alert Message; if null, AdapTable creates dynamically using Rule & Scope |
| [MessageType](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#messagetype) | [`AdaptableMessageType`](https://www.adaptabletools.com/docs/reference/adaptablemessagetype.md) | Type of Alert: 'Info', 'Success', 'Warning', 'Error'; influences Alert colour, icon and logging |
| [Name](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#name) | `string` | Name of the Alert Definition |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
| [IsSuspended](https://www.adaptabletools.com/docs/reference/alertdefinitionbase.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object |
And both contain an `AlertProperties` object which derives from [`Alert Presentation Properties`](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md) and defines some optional behaviour for the Alert:
| Property | Type | Description |
| --- | --- | --- |
| [DisplayNotification](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#displaynotification) | `boolean` | Displays a notification when Alert is triggered |
| [DisplaySystemStatusMessage](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#displaysystemstatusmessage) | `boolean` | Shows the alert message in the System Status panel |
| [LogToConsole](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#logtoconsole) | `boolean` | Logs the Alert message to the console |
| [NotificationDuration](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#notificationduration) | [`NotificationsOptions`](https://www.adaptabletools.com/docs/reference/notificationsoptions.md)`['duration']` | Notifiction duration(defaults to `NotificationOptions.duration`) |
| [ShowInDiv](https://www.adaptabletools.com/docs/reference/alertpresentationproperties.md#showindiv) | `boolean` | Shows Alert text in the div specificed in `alertContainer` property of Container Options |
### Rule Based Alert Definition
The [`Rules Based Alert Definition`](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md) is used for Alerts with Expressions and Scope:
| Property | Type | Description |
| --- | --- | --- |
| [AlertForm](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md#alertform) | `string \| `[`AlertButtonForm`](https://www.adaptabletools.com/docs/reference/alertbuttonform.md) | Form to display in Alert with buttons and inputs |
| [AlertProperties](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md#alertproperties) | [`RuleAlertProperties`](https://www.adaptabletools.com/docs/reference/rulealertproperties.md) | Properties which set what happens when the Alert is triggered (notification and grid behaviours) |
| [Rule](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md#rule) | [`AlertRule`](https://www.adaptabletools.com/docs/reference/alertrule.md) | When Alert should be triggered |
| [Scope](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Where Alert can be triggered: one, some or all columns or DataTypes |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
| [IsSuspended](https://www.adaptabletools.com/docs/reference/rulebasedalertdefinition.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object |
And it has these Alert Properties of type [`RuleAlertProperties`](https://www.adaptabletools.com/docs/reference/rulealertproperties.md) defined as follows:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [HighlightCell](https://www.adaptabletools.com/docs/reference/rulealertproperties.md#highlightcell) | `boolean \| `[`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Colours updated Row using `MessageType` of triggering Alert Definition | |
| [HighlightRow](https://www.adaptabletools.com/docs/reference/rulealertproperties.md#highlightrow) | `boolean \| `[`AdaptableStyle`](https://www.adaptabletools.com/docs/reference/adaptablestyle.md) | Colours updated Row using `MessageType` of triggering Alert Definition | |
| [JumpToCell](https://www.adaptabletools.com/docs/reference/rulealertproperties.md#jumptocell) | `boolean` | Grid will 'jump' to the changed cell which triggered the Alert | |
| [JumpToRow](https://www.adaptabletools.com/docs/reference/rulealertproperties.md#jumptorow) | `boolean` | Grid will 'jump' to the newly added row which triggered the Alert | |
| [PreventEdit](https://www.adaptabletools.com/docs/reference/rulealertproperties.md#preventedit) | `boolean` | Automatically prevent any cell edit which triggered the Alert (i.e. validation) | false |
### Schedule Based Alert Definition
The [`Schedule Alert Definition`](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md) is used for Alerts that run on a Schedule:
| Property | Type | Description |
| --- | --- | --- |
| [AlertProperties](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#alertproperties) | [`ScheduledAlertProperties`](https://www.adaptabletools.com/docs/reference/scheduledalertproperties.md) | Notification properties for scheduled alerts (no grid behaviours) |
| [Schedule](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#schedule) | [`Schedule`](https://www.adaptabletools.com/docs/reference/schedule.md) | When the alert should run |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
| [IsSuspended](https://www.adaptabletools.com/docs/reference/scheduledalertdefinition.md#issuspended) | `boolean` | Suspends (i.e. turns off) an Adaptable Object |
And it has these Alert Properties of type [`ScheduledAlertProperties`](https://www.adaptabletools.com/docs/reference/scheduledalertproperties.md) defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [IncludeSuspendButton](https://www.adaptabletools.com/docs/reference/scheduledalertproperties.md#includesuspendbutton) | `boolean` | When true, the scheduled notification includes a Suspend button |
------------------
## Alert Options
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [alertForms](https://www.adaptabletools.com/docs/reference/alertoptions.md#alertforms) | [`AlertForm`](https://www.adaptabletools.com/docs/reference/alertform.md)`[]` | Full definitions of Alert Forms - the names of which are provided in Alert State | |
| [alertMessageHeader](https://www.adaptabletools.com/docs/reference/alertoptions.md#alertmessageheader) | `(alertMessageContext: `[`AlertMessageContext`](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md)`) => string \| undefined` | Function providing Header to display in Alert; if empty, AdapTable provides dynamically | |
| [alertMessageText](https://www.adaptabletools.com/docs/reference/alertoptions.md#alertmessagetext) | `(alertMessageContext: `[`AlertMessageContext`](https://www.adaptabletools.com/docs/reference/alertmessagecontext.md)`) => string \| undefined` | Function providing Message to display in Alert; if empty, AdapTable provides dynamically | |
| [cellHighlightDuration](https://www.adaptabletools.com/docs/reference/alertoptions.md#cellhighlightduration) | `number` | How long (in ms) a Cell will be highlighted when an Alert fires | 2000 |
| [commandHandlers](https://www.adaptabletools.com/docs/reference/alertoptions.md#commandhandlers) | [`CommandHandler`](https://www.adaptabletools.com/docs/reference/commandhandler.md)`[]` | Custom onClick Handlers for Buttons (displayed in Alert Forms) | |
| [consolidateBatchAlerts](https://www.adaptabletools.com/docs/reference/alertoptions.md#consolidatebatchalerts) | `boolean` | When a single batch action (e.g. Bulk Update, Smart Edit) triggers multiple Alerts from the same Alert Definition, consolidate them into a single Alert (with an occurrence count) rather than showing one Alert per changed cell. | true |
| [dataChangeDetectionPolicy](https://www.adaptabletools.com/docs/reference/alertoptions.md#datachangedetectionpolicy) | [`DataChangeDetectionPolicy`](https://www.adaptabletools.com/docs/reference/datachangedetectionpolicy.md) | Whether Alert rule is evaluated against the `rawValue` or `formattedValue` of the changed cell data | 'rawValue' |
| [maxAlertsInStore](https://www.adaptabletools.com/docs/reference/alertoptions.md#maxalertsinstore) | `number` | How many alerts held in State at any one time; when limit is breached, oldest alert will be removed | 20 |
| [rowHighlightDuration](https://www.adaptabletools.com/docs/reference/alertoptions.md#rowhighlightduration) | `number` | How long (in ms) a Row will be highlighted when an Alert Fires | 4000 |
| [showMissingPrimaryKeyAlert](https://www.adaptabletools.com/docs/reference/alertoptions.md#showmissingprimarykeyalert) | `boolean` | Shows Alert if Primary Key column in Adaptable Options is not present or incorrect | false |
| [statusbarHighlightDuration](https://www.adaptabletools.com/docs/reference/alertoptions.md#statusbarhighlightduration) | `number` | How long (in ms) Alert panel in Status Bar highlights when an Alert Fires | 2000 |
------------------------
## Alert API
Full programmatic access to Alerts and related features is available in [Alert API](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md).
This enables Alerts to be accessed, created, edited, deleted and shared programmatically.
| Method | Returns | Description |
| --- | --- | --- |
| [addAlertDefinition(alertDefinition)](https://www.adaptabletools.com/docs/reference/alertapi.md#addalertdefinition) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Adds given Alert Definition to Adaptable State |
| [applyScheduledAlertDefinition(alertDefinition)](https://www.adaptabletools.com/docs/reference/alertapi.md#applyscheduledalertdefinition) | `void` | Fires a scheduled alert definition (notification, system status, etc.) |
| [deleteAlertDefinition(alertDefinition)](https://www.adaptabletools.com/docs/reference/alertapi.md#deletealertdefinition) | `void` | Deletes given Alert Definition from Adaptable State |
| [displayAdaptableAlert(alertToShow)](https://www.adaptabletools.com/docs/reference/alertapi.md#displayadaptablealert) | `Promise` | Displays the given Adaptable Alert |
| [displayAdaptableAlertNotification(alert)](https://www.adaptabletools.com/docs/reference/alertapi.md#displayadaptablealertnotification) | `void` | Displays given Alert as a Toast |
| [editAlertDefinition(alertDefinition)](https://www.adaptabletools.com/docs/reference/alertapi.md#editalertdefinition) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Updates given Alert Definition in Adaptable State |
| [evaluateAlertDefinitions(alertDefinitions)](https://www.adaptabletools.com/docs/reference/alertapi.md#evaluatealertdefinitions) | `void` | Evaluates the given Alert Definitions - will fire Alert if rule is met |
| [findAlertDefinitions(alertLookupCriteria)](https://www.adaptabletools.com/docs/reference/alertapi.md#findalertdefinitions) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md)`[]` | Find all Alert Definitions which match the given criteria |
| [getActiveAlertDefinitions(config)](https://www.adaptabletools.com/docs/reference/alertapi.md#getactivealertdefinitions) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md)`[]` | Retrieves all Alert Definitions which are currently active |
| [getAlertDefinitionById(id, config)](https://www.adaptabletools.com/docs/reference/alertapi.md#getalertdefinitionbyid) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Retrieves alert definition by the technical ID (from `AlertState`) |
| [getAlertDefinitionByName(name)](https://www.adaptabletools.com/docs/reference/alertapi.md#getalertdefinitionbyname) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md)` \| undefined` | Retrieves an Alert Definition by its Name |
| [getAlertDefinitions(config)](https://www.adaptabletools.com/docs/reference/alertapi.md#getalertdefinitions) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md)`[]` | Retrieves all Alert Definitions in Alert State |
| [getAlertState()](https://www.adaptabletools.com/docs/reference/alertapi.md#getalertstate) | [`AlertState`](https://www.adaptabletools.com/docs/reference/alertstate.md) | Retrieves Alert section from Adaptable State |
| [getSuspendedAlertDefinitions(config)](https://www.adaptabletools.com/docs/reference/alertapi.md#getsuspendedalertdefinitions) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md)`[]` | Retrieves all Alert Definitions which are currently suspended |
| [openAlertSettingsPanel(tab)](https://www.adaptabletools.com/docs/reference/alertapi.md#openalertsettingspanel) | `void` | Opens the Settings Panel on the Alert page. |
| [showAlert(alertHeader, alertMessage, messageType, alertProperties)](https://www.adaptabletools.com/docs/reference/alertapi.md#showalert) | `Promise` | Creates Alert based on given parameters and displays it. |
| [showAlertError(alertHeader, alertMessage)](https://www.adaptabletools.com/docs/reference/alertapi.md#showalerterror) | `Promise` | Creates an Adaptable Alert based on given parameters and displays it as Error Alert. |
| [showAlertInfo(alertHeader, alertMessage)](https://www.adaptabletools.com/docs/reference/alertapi.md#showalertinfo) | `Promise` | Creates an Adaptable Alert based on given parameters and displays it as Info Alert. |
| [showAlertSuccess(alertHeader, alertMessage)](https://www.adaptabletools.com/docs/reference/alertapi.md#showalertsuccess) | `Promise` | Creates an Adaptable Alert based on given parameters and displays it as Succcess Alert. |
| [showAlertWarning(alertHeader, alertMessage)](https://www.adaptabletools.com/docs/reference/alertapi.md#showalertwarning) | `Promise` | Creates an Adaptable Alert based on given parameters and displays it as Warning Alert. |
| [suspendAlertDefinition(alertDefinition)](https://www.adaptabletools.com/docs/reference/alertapi.md#suspendalertdefinition) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Suspends Alert Definition |
| [suspendAllAlertDefinition()](https://www.adaptabletools.com/docs/reference/alertapi.md#suspendallalertdefinition) | `void` | Suspends all Alert Definitions |
| [unSuspendAlertDefinition(alertDefinition)](https://www.adaptabletools.com/docs/reference/alertapi.md#unsuspendalertdefinition) | [`AlertDefinition`](https://www.adaptabletools.com/docs/reference/alertdefinition.md) | Activates a suspended Alert Definition |
| [unSuspendAllAlertDefinition()](https://www.adaptabletools.com/docs/reference/alertapi.md#unsuspendallalertdefinition) | `void` | Activates all suspended Alert Definition |
------------------
## Alert Fired Event
The [Alert Fired Event](https://www.adaptabletools.com/docs/handbook-alerting-alert-fired-event/index.md) is published by AdapTable whenever an Alert is fired.
---
# Validation Alerts
Canonical page: https://www.adaptabletools.com/docs/handbook-alerting-validation
- Validation Alerts can prevent bad edits
- They will fire before the edit is committed, preventing a round trip to the server
Validation Alerts can be used to **prevent cell edits** which break the rule set in the [Alert Definition](https://www.adaptabletools.com/docs/handbook-alerting-technical-reference/index.md).
This is done by specifying `PreventEdit` in the `AlertProperties` property to _true_.
If a Prevent Edit Alert is too inflexible, an Alert with a an `Undo` Action can be used instead
Validation Alerts are designed to avoid this common, and extremely annoying, scenario:
1. an edit is made and commmitted
2. all other users of the application see this edit
3. server validation then kicks in and forces the cell to 'jump back' to its initial value in all users' grids
- An alternative to validation Alerts is to create an Alert with a [custom form](https://www.adaptabletools.com/docs/handbook-alerting-notifications/index.md) enabling users to provide a new value
- This can be achieved via an [Adaptable Form](https://www.adaptabletools.com/docs/ui-tutorial-configuring-adaptable-forms/index.md) with 2 [Buttons](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) that reference [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md) methods when clicked
**Example: Alerts: Validation Alerts**
Alerts which prevent cell edits
- This example contains a Validation Alert which prevents a cell edit which sets `Github Stars` to 0
- It is of type `Error` and displays a Notification when the Alert fires
### Expand to see the Alert Definition
```tsx
Alert: {
AlertDefinitions: [
{
Name: 'alert-github_stars',
MessageType: 'Error',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicate: {
PredicateId: 'Equals',
Inputs: [0],
},
},
AlertProperties: {
PreventEdit: true,
DisplayNotification: true,
},
},
],
},
```
- Set a `GitHub Stars` value to 0 and see the change being reverted and the Alert notification displayed
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Alert Prevent Cell Edit',
notificationsOptions: {
position: 'TopCenter',
},
initialState: {
Dashboard: {
ModuleButtons: ['Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Alert: {
AlertDefinitions: [
{
Name: 'alert-github-stars',
MessageType: 'Error',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'Equals',
Inputs: [0],
},
],
},
AlertProperties: {
PreventEdit: true,
DisplayNotification: true,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column
- Calculated Columns are _special_ columns which display a _calculated_ value
- Unlike _regular_ columns, Calculated Columns do not display data from AG Grid's data source
- Instead, the displayed values are derived _(calculated)_ from other columns
- The calculation takes the form of an AdapTableQL Expression
- This is evaluated and kept in sync with the live data
- The Expression always returns a single value and can be (depending on the complexity required):
- `Standard` - value returned is based on other cells in the row
- `Aggregated` - value returned is based on other rows in the Grid
- `Cumulative` - uses an Aggregation operation applied cumulatively to rows in specific order
- `Quantile` - value is derived from other rows using quantile aggregation
- Once created a Calculated Column can be used and managed like any other Column in AG Grid
Calculated Columns are a special type of column which display a an **evaluated** value for each cell.
The Calculated Column definition contains an [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) which is evaluated dynamically by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md).
The Expression is typically a Standard Expression (i.e. it evaluates the cell based on other columns in the row).
But there are more complicated Expressions types available for more advanced scenarios including [Aggregated](https://www.adaptabletools.com/docs/handbook-calculated-column-aggregated/index.md), [Cumulative](https://www.adaptabletools.com/docs/handbook-calculated-column-cumulative/index.md) and [Quantile](https://www.adaptabletools.com/docs/handbook-calculated-column-quantile/index.md) Calculated Columns.
It is valid for a Calculated Column to display a *static* value, rather than an [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md), though this is a rare use case
Once created, Calculated Columns are treated as regular columns in AdapTable.
These columns do not exist in the underlying AG Grid data source but are still stored with [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
- Calculated Columns - like [Free Text Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) and [Action Columns](https://www.adaptabletools.com/docs/handbook-action-column/index.md) - are not "normal" data columns
- Instead they are **created dynamically** by AdapTable each time the Application runs
- By contrast [Styled Columns](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) are "normal" data columns, albeit ones which AdapTable specially renders
## Calculated Column Value
The value displayed in the Calculated Column can be one of 4 types: string, number, date or boolean.
When creating a Calculated Column in the UI, AdapTable will infer the DataType from the Expression result.
- The run-time user can override this inferred result if required
- For Calculated Colunns provided via Initial Adaptable State, there is a **mandatory** `DataType` property
### How Calculated Columns Work in AdapTable
Each time the application starts up AdapTable retrieves any Calculated Column definitions from Adaptable State.
For each Calculated Column definition, AdapTable will:
1. Create a [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) with the properties set based on the Definition
2. Either create an equivalent AG Grid column if one is not provided...
3. ...or update an existing AG Grid column (which has a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md#special-columns) of *calculatedColumn*)
4. Create a [ValueGetter](https://www.ag-grid.com/javascript-data-grid/value-getters) for the Column which will invoke the Expression when needed and return the scalar value
5. Keep the Calculated Column value in sync with the referenced column values
## Calculated Column Expressions
Each Calculated Column definition contains a `Query` property, responsible for providing each cell value.
The Query wraps an **Expression** which is evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) for each cell in the column.
- Sometimes developers want to evaluate the Calculated Column themselves, rather letting AdapTable via do it
- To do this, return 'false' for *CalculatedColumn* in the `evaluateAdaptableQLExternally` property in [Expression Options](https://www.adaptabletools.com/docs/adaptable-ql-expression-technical-reference/index.md)
There are 4 types of Expressions available when using Calculated Columns:
All are *Scalar* meaning the return value can be of **any** type
| Calculation Type | How Calculated Value is Returned |
| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| [Standard](https://www.adaptabletools.com/docs/handbook-calculated-column-standard/index.md) | Based solely on data in the current row |
| [Aggregation](https://www.adaptabletools.com/docs/handbook-calculated-column-aggregated/index.md) | Derived from multiple, distinct rows (with optional grouping) |
| [Cumulative](https://www.adaptabletools.com/docs/handbook-calculated-column-cumulative/index.md) | Aggregation Operation is applied to each row cumulatively in specific order |
| [Quantile](https://www.adaptabletools.com/docs/handbook-calculated-column-quantile/index.md) | Aggregated Values are placed into ordered buckets |
**Example: Calculated Columns: Introducing**
Calculated Columns: How they work
- This demo contains 3 (Numeric) Calculated Columns:
- `Total PRs` - sums the `Open PRs` and `Closed PRs` Columns
- `Issues Open/Total Ratio` - Divides `OpenIssues` by sum of `OpenIssues` and `ClosedIssues`
- `Sum Pop by Lang` - uses an Aggregation Expression to sum `Github Stars` grouped by `Language`
### Expand to see the Calculated Column Definitions
```ts
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Total PRs',
ColumnId: 'total_pr_count',
Query: {
ScalarExpression: '[open_pr_count] + [closed_pr_count]',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Issues Open/Total Ratio',
ColumnId: 'open-total-issue-ratio',
Query: {
ScalarExpression: '[open_issues_count] / ([open_issues_count] +[closed_issues_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'sum-popularity-by-lang',
FriendlyName: 'Sum Pop by Lang',
Query: {
AggregatedScalarExpression: 'SUM([github_watchers], GROUP_BY([language]))',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Basic Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'open_pr_count',
'closed_pr_count',
'total_pr_count',
'open_issues_count',
'closed_issues_count',
'open-total-issue-ratio',
'github_watchers',
'language',
'sum-popularity-by-lang',
'licence',
'github_stars',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Total PRs',
ColumnId: 'total_pr_count',
Query: {
ScalarExpression: '[open_pr_count] + [closed_pr_count]',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
},
},
{
FriendlyName: 'Issues Open/Total Ratio',
ColumnId: 'open-total-issue-ratio',
Query: {
ScalarExpression:
'[open_issues_count] / ([open_issues_count] +[closed_issues_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'sum-popularity-by-lang',
FriendlyName: 'Sum Pop by Lang',
Query: {
AggregatedScalarExpression:
'SUM([github_watchers], GROUP_BY([language]))',
},
CalculatedColumnSettings: {
DataType: 'number',
Groupable: true,
},
},
],
},
},
};
```
## Creating Calculated Columns
Calculated Columns, like most AdapTable Objects, can be created in 2 ways:
- defined at design-time in [Calculated Column Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference/index.md)
- created at run-time using the [Calculated Column Wizard](#using-calculated-columns)
Once created, Calculated Columns are stored in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) (like all [Adaptable Objects](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects)).
- Only the Calculated Column **Definition** (e.g. Name, Expression, DataType etc) is stored in AdapTable State
- AdapTable does not store any actual cell data
## Formatting Calculated Columns
As stated above Calculated Columns, once created or defined, are treated like any other AdapTable Column.
This means, for example, that they can be used to trigger Alerts, or be included in Reports in Export.
It also allows Calculated Columns to be [fully formatted](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) with Styles, Display Formats and Conditions.
This allows rendering a Calculated Column as a [Sparkline](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md) (typically by using the `TO_ARRAY` [Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md))
**Example: Calculated Columns: Formatting**
Calculated Columns: Adding Formatting
- This demo contains 5 Calculated Columns each of which has been been styled:
- Three Columns have been given [Column Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md), some with Conditions:
- `Subscribers Ratio` - has 2 fraction digits and a suffix of '%'
- `Total PRs` - is right-aligned and italicised. Also has a Condition to show 'K' (with blue font) where > 1000
- `Years Old` - has a suffix of "years". Also has a Condition to show purple with white font where value is > 10
- Two Columns have had a [Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) applied:
- `Big Stars` - has a [Percent Bar Style](https://www.adaptabletools.com/docs/handbook-styled-column-percent-bar/index.md)
- `Stats` - uses the `TO_ARRAY` function and then renders a [Sparkline Column](https://www.adaptabletools.com/docs/handbook-styled-column-sparkline/index.md)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Formatting Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: [
'CalculatedColumn',
'FormatColumn',
'StyledColumn',
'SettingsPanel',
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'subscribersRatio',
'licence',
'total_pr_count',
'github_stars',
'yearsOld',
'bigStars',
'language',
'stats',
'github_watchers',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Subscribers Ratio',
ColumnId: 'subscribersRatio',
Query: {
ScalarExpression: '[github_stars] / [github_watchers]',
},
CalculatedColumnSettings: {
ColumnTypes: ['first'],
Filterable: true,
Groupable: true,
DataType: 'number',
},
},
{
FriendlyName: 'Total PRs',
ColumnId: 'total_pr_count',
Query: {
ScalarExpression: '[open_pr_count] + [closed_pr_count]',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
FriendlyName: 'Years Old',
ColumnId: 'yearsOld',
Query: {
ScalarExpression: 'DIFF_YEARS(CURRENT_DAY(), [created_at])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Big Stars',
ColumnId: 'bigStars',
Query: {
ScalarExpression: '[github_watchers] * 5',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'stats',
FriendlyName: 'Stats',
Query: {
ScalarExpression:
'TO_ARRAY([closed_pr_count], [closed_pr_count], [open_issues_count], [closed_issues_count])',
},
CalculatedColumnSettings: {
Resizable: true,
DataType: 'numberArray',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-subscribersRatio',
Scope: {
ColumnIds: ['subscribersRatio'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
Suffix: '%',
},
},
},
{
Name: 'formatColumn-total_pr_count',
Scope: {
ColumnIds: ['total_pr_count'],
},
Style: {
FontStyle: 'Italic',
Alignment: 'Right',
},
},
{
Name: 'formatColumn-total_pr_count',
Scope: {
ColumnIds: ['total_pr_count'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [1000],
},
],
},
Style: {
ForeColor: 'LightBlue',
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Multiplier: 0.001,
Suffix: 'K',
},
},
},
{
Name: 'formatColumn-yearsOld',
Scope: {
ColumnIds: ['yearsOld'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [10],
},
],
},
Style: {
BackColor: 'Purple',
ForeColor: 'White',
},
},
{
Name: 'formatColumn-yearsOld',
Scope: {
ColumnIds: ['yearsOld'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Suffix: ' years',
},
},
},
],
},
StyledColumn: {
StyledColumns: [
{
Name: 'stats Sparkline',
ColumnId: 'stats',
SparklineStyle: {
options: {
type: 'area',
fill: 'rgba(216, 204, 235, 0.3)',
stroke: 'rgb(119,77,185)',
axis: {
type: 'category',
stroke: 'rgb(204, 204, 235)',
},
},
},
},
{
Name: 'bigStars PercentBar',
ColumnId: 'bigStars',
PercentBarStyle: {
RangeValueType: 'Number',
CellRanges: [
{
Min: 'Col-Min',
Max: 'Col-Max',
Color: 'green',
},
],
BackColor: '#d3d3d3',
},
},
],
},
},
};
```
## Referencing Calculated Columns
Another beneficial consequence of Calculated Columns being treated like any other AdapTable Column is that any Calculated Column's Expression can reference other Calculated Columns in the Grid if required.
For instance Calculated Columns can be referenced in [Charts](https://www.adaptabletools.com/docs/handbook-charts/index.md), [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) and [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md).
- If a column referenced in the Calculated Column's Expression updates, the Calculated Column's value updates
- As a result, the Chart renders or the Alert triggers or the Cell flashes
- See [Referencing Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column-referencing/index.md) for further details
## Pivoting Calculated Columns
Because Calculated Columns are essentially regular columns, they can also be used in [Pivot Layouts](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md).
They can be referenced in 3 ways when pivoting:
- **Row Group Columns** - AG Grid will display one row for each distinct value in the Calculated Column
- **Pivoted Columns** - AG Grid automatically creates a column for each distinct value in the Calculated Column
- **Aggregation Columns** - AG Grid will display the supplied `aggFunc` (typically `sum` but can be anything)
**Example: Pivoting Calculated Columns**
Using Calculated Columns inside Pivot Layouts
- This Demo contains a [Pivot Layout](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md) with 3 Calculated Columns each used as a different element in a Pivot Layout:
- `Total` (Aggregated Column)
- adds the values of `Github Stars`and `Github Watchers` columns
- is used as an **Aggregated Column** in the Layout
- contains the `sum` aggregation
- `Popularity` (Pivot Column)
- uses Ternary Logic to say whether the framework is popular (based on the value in `Github Watchers`)
- Used as a **Pivot Column** in the Layout
- Note: AG Grid automatically creates one dynamic, pivoted column for each of the 2 distinct Calculated Column values ('Popular', 'Unpopular')
- `Favourites` (Row Grouped Column)
- uses Ternary Logic to say whether framework is a favourite (i.e. is one of "react", "angular", "vue", "stencil")
- This is used as a **Row Group** in the Layout
- Note: AG Grid automatically creates one grouped row for each of the 2 distinct Calculated Column values ('Main', 'Other')
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Pivoted Calculated Columns',
initialState: {
Dashboard: {
Tabs: [{Name: 'Demo', Toolbars: ['Layout']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'Total',
Query: {
ScalarExpression: '[github_watchers] + [github_stars]',
},
CalculatedColumnSettings: {
DataType: 'number',
Aggregatable: true,
Filterable: false,
},
},
{
ColumnId: 'Popularity',
Query: {
ScalarExpression:
'[github_watchers] > 500 ? "Popular" : "Unpopular" ',
},
CalculatedColumnSettings: {
DataType: 'boolean',
Pivotable: true,
Filterable: false,
},
},
{
ColumnId: 'Favourites',
Query: {
ScalarExpression:
'[name] IN ("react", "angular", "vue", "stencil") ? "Main" : "Other" ',
},
CalculatedColumnSettings: {
DataType: 'boolean',
Groupable: true,
Filterable: false,
},
},
],
},
Layout: {
CurrentLayout: 'Pivot Layout',
Layouts: [
{
Name: 'Pivot Layout',
PivotColumns: ['Popularity'],
PivotGroupedColumns: ['Favourites'],
SuppressAggFuncInHeader: true,
PivotAggregationColumns: [
{
ColumnId: 'github_watchers',
AggFunc: 'sum',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'Total',
AggFunc: 'sum',
},
],
},
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'github_watchers',
'language',
'Total',
'Popularity',
'Favourites',
'updated_at',
'description',
'created_at',
'has_wiki',
'pushed_at',
'open_issues_count',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {ColDef, GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData, WebFramework} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({agGridApi}: AdaptableReadyInfo) => {
agGridApi.openToolPanel('columns');
};
```
## Calculated Columns Performance
Calculated Columns are designed to be very performant.
However a very large Data Set, with multiple Calculated Columns that reference other Calculated Columns, might present a performance hit.
This could be be particularly noticeable when sorting a column and AG Grid's [Value Cache](https://www.ag-grid.com/javascript-data-grid/value-getters/#value-cache) is unset
This is because a Calculated Column contains a [Value Getter](https://www.ag-grid.com/javascript-data-grid/value-getters) which is invoked each time a value is needed.
So when sorting a Column the same Value Getter will be called many times repeatedly.
- In such scenarios, consider setting `valueCache` to *true* in AG Grid GridOptions
- This will enable the [Value Getter Cache](https://www.ag-grid.com/javascript-data-grid/value-getters/#value-cache) (which comes with various Expiry options)
## Using Calculated Columns
Run time users are able to create, edit, delete and share Calculated Columns via the Calculated Column section of the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md).
This displays a list of existing Calculated Columns with buttons to edit, share or delete each item.
- There is no *Suspend* Button as Calculated Columns **cannot** be suspended
- AdapTable will try to prevent you from *deleting* a Calculated Column which is referenced elsewhere
There is also an Add button to create new Calculated Columns using the Calculated Column Wizard.
- Newly created Calculated Columns are automatically added to the end of the Current [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md)
- Existing Calculated Columns include an `Edit Calculated Column` Menu Item in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md)
### Using the Calculated Column Wizard
There are a few steps required when creating a Calculated Column:
There are 4 types of Calculated Column which can be created (using the [Expression Editor](https://www.adaptabletools.com/docs/ui-expression-editor/index.md)):
- Standard - value is derived from other cells in Row
- Aggregated - value is derived from aggregating multiple rows
- Cumulative - value is derived cumulatively from other rows
- Quantile - value is derived using quantile aggregations
The Calculated Column Definition step requires 3 properties to be provided:
- `Column Id` - this is the value used to refer to the Calculated Column in the AdapTable UI.
- `Name` (optional) - how the column will be referenced and what to appear in the Column's Header
This property will default to the `ColumnId` value, so only set this if you need it to be different
- Header Tooltip (optional) - a Tooltip to display in the Column's Header
The Expression Editor is a powerful UI tool designed to make writing Expressions easy, including:
- a dropdown that provides all the Expression Functions available
- context sensitive help
- validation
There are 2 settings that can be provided:
- `DataType` - this is the DataType you require for the Column. Options are:
- String (the default)
- Number
- Date
- Boolean
AdapTable will infer this from the Expression set in the previous stage, so only override if required
- `Column Width` - how wide the Calculated Column should be
If left empty, the width will be set by AG Grid based on the other column definitions
There is a set properties that can be configured for the Calculated Column:
- `Filterable`
- `Resizable`
- `Groupable`
- `Sortable`
- `Pivotable`
- `Aggregatable`
- `Suppress Menu`
- `Suppress Movable`
- `Editable` (always false)
All properties are false by default so check an option to turn on a feature
In addition any options that have been supplied in the `columnTypes` property of [Column Options](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md#columntypes) will also be displayed.
The new Calculated Column will be created, and will be added to the end of the Current [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md).
It will be given, where applicable, any properties defined in AG Grid DefaultColDef.
## Defining Calculated Columns
Calculated Columns can be defined by developers via [Calculated Column Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference/index.md).
Each `CalculatedTextColumn` object contains 3 main sets of properties to:
- uniquely identify and name the Calculated Column
- provide the Expression which is to be evaluated
- describe the behaviour of the Column
### Anatomy of a Calculated Column
The [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md) object is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [CalculatedColumnSettings](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#calculatedcolumnsettings) | [`CalculatedColumnSettings`](https://www.adaptabletools.com/docs/reference/calculatedcolumnsettings.md) | Additional optional properties for Column (e.g. filterable, resizable) |
| [ColumnId](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#columnid) | `string` | Name of Calculated Column |
| [FriendlyName](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#friendlyname) | `string` | Name to be used in Column Header; if blank `ColumnId` is used |
| [Query](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#query) | [`AdaptableCalculatedColumnQuery`](https://www.adaptabletools.com/docs/reference/adaptablecalculatedcolumnquery.md) | Scalar/AggregatedScalar Query used by AdapTableQL to evaluate Column's value |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
Calculated Column Settings
The [`CalculatedColumnSettings`](https://www.adaptabletools.com/docs/reference/calculatedcolumnsettings.md) object inherits from the base [`SpecialColumnSettings`](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md) which is defined as follows:
`DataType` is the only mandatory property
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [Aggregatable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#aggregatable) | `boolean` | Whether Column can be used in an aggregation when grouping | false |
| [ColumnTypes](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#columntypes) | `string[]` | Custom column types added to AG Grid Column Types when object is created | |
| [DataType](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#datatype) | [`AdaptableColumnDataType`](https://www.adaptabletools.com/docs/reference/adaptablecolumndatatype.md) | Expression's return value DataType, only mandatory property | |
| [Filterable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#filterable) | `boolean` | Whether Column is filterable | false |
| [Groupable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#groupable) | `boolean` | Whether Column can be grouped | false |
| [HeaderToolTip](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#headertooltip) | `string` | Tooltip to show in the Column Header (not cells) | |
| [Pivotable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#pivotable) | `boolean` | Whether Column can be used when grid is in pivot mode | false |
| [Resizable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#resizable) | `boolean` | Whether Column can be resized (by dragging column header edges) | false |
| [Sortable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#sortable) | `boolean` | Whether Column is sortable | false |
| [SuppressMenu](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#suppressmenu) | `boolean` | Whether if no menu should be shown for this Column header. | false |
| [SuppressMovable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#suppressmovable) | `boolean` | Whether if this Column should be movable via dragging | false |
| [Width](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#width) | `number` | Preferred (pixel) Column Width; if unset, calculated dynamically by AG Grid | |
There is one additional, optional property added for Calculated Column:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [ShowToolTip](https://www.adaptabletools.com/docs/reference/calculatedcolumnsettings.md#showtooltip) | `boolean` | Show underlying Expression as Tooltip when hovering over a cell | false |
Worked examples of how to define each kind of Calculated Column are on the type-specific pages: [Standard](https://www.adaptabletools.com/docs/handbook-calculated-column-standard/index.md), [Aggregated](https://www.adaptabletools.com/docs/handbook-calculated-column-aggregated/index.md), [Cumulative](https://www.adaptabletools.com/docs/handbook-calculated-column-cumulative/index.md) and [Quantile](https://www.adaptabletools.com/docs/handbook-calculated-column-quantile/index.md).
Disallow filtering on **all** Calculated Columns by setting `enableFilterOnSpecialColumns` to *false* in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
## AG Grid Definitions
Calculated columns are typically **not** provided in the `ColDefs` property in AG Grid GridOptions.
Instead, the definition provided in Initial State suffices for AdapTable to be able to create the associated AG Grid column automatically.
However sometimes a developer might want to add an AG Grid element to the column.
For instance a tooltip might be needed, or there might be a requirement to put the Calculated Column inside a Column Group (which is an AG Grid feature).
This is possible: a column can be provided in AG Grid ColDefs but by specifying a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) of `calculatedColumn`, AdapTable will automatically wire it up with an associated Calculated Column definition.
- Set the [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) to be `calculatedColumn`
- The `ColId` in the Column Definition and `ColumnId` in the Calculated Column definition must be the same value
**Example: Calculated Columns: Defining in AG Grid**
Calculated Columns: Adding AG Grid properties
- This demo contains an AG Grid Column Group - `Github Averages`
- The group contains 2 Calculated Columns `Github Avg By Language` and `Github Avg By Licence`
- Both the [Column Group](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md) and the 2 containing Columns were defined in AG Grid Column Defs
- The 2 columns in the Group were given AG Grid Header and Cell ToolTips
- They were also given a type of `calculatedColumn` which is what allowed AdapTable to wire everything together
- Hover over a cell in the Calculated Column and see the Tooltip which AG Grid provides
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Defining Calculated Columns in AG Grid',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'FormatColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'github_stars',
'license',
'language',
'starsAvgByLanguage',
'starsAvgByLicence',
'github_watchers',
],
Name: 'Standard Layout',
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'starsAvgByLanguage',
Query: {
AggregatedScalarExpression:
'AVG([github_stars] ,GROUP_BY([language] ) ) ',
},
FriendlyName: 'Github Avg By Language',
CalculatedColumnSettings: {DataType: 'number'},
},
{
ColumnId: 'starsAvgByLicence',
Query: {
AggregatedScalarExpression:
'AVG([github_stars] ,GROUP_BY([license] ) ) ',
},
FriendlyName: 'Github Avg By Licence',
CalculatedColumnSettings: {DataType: 'number'},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-starsAvgByLanguage',
Scope: {
ColumnIds: ['starsAvgByLanguage', 'starsAvgByLicence'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
```ts
import {ColDef, ColGroupDef, ITooltipParams} from 'ag-grid-enterprise';
export const columnDefs: (ColDef | ColGroupDef)[] = [
{
field: 'name',
cellDataType: 'text',
sortable: true,
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
field: 'license',
cellDataType: 'text',
editable: false,
enablePivot: true,
enableRowGroup: true,
},
{
headerName: 'Github Averages',
children: [
{
colId: 'starsAvgByLanguage',
type: ['calculatedColumn'],
cellDataType: 'number',
headerTooltip:
"Shows all the Github Stars for the framework's language",
tooltipValueGetter: (params: ITooltipParams) => {
return 'All Stars for ' + params.data.language;
},
},
{
colId: 'starsAvgByLicence',
type: ['calculatedColumn'],
cellDataType: 'number',
headerTooltip: "Shows all the Github Stars for the framework's licence",
tooltipValueGetter: (params: ITooltipParams) => {
return 'All Stars for ' + params.data.license;
},
},
],
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{
field: 'has_wiki',
headerName: 'Has Wiki',
cellDataType: 'boolean',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
];
```
See [Adding Column Types for Special Columns](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) for more details and a demo
## UI Entitlements
The [UI Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning/index.md) behaviour for Calculated Columns is as expected for `Full` and `Hidden` [`Access Levels`](https://www.adaptabletools.com/docs/reference/accesslevel.md).
The `ReadOnly` Entitlement behaviour is that Calculated Columns will display (and [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) will evaluate their values) but Users are not permitted to edit or delete them.
## Calculated Column Changed Event
The [Calculated Column Changed Event](https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference/index.md) fires whenever anything changes in Calculated Column State, i.e. if a Calculated Column has been added, edited or deleted.
The Event includes details of the Action that triggered the Event and the associated Calculated Column.
This is particularly useful if you are [evaluating Calculated Columns on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md)
---
# Aggregated Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-aggregated
- Aggregated Calculated Columns show a value that is derived dynamically from __multiple, distinct rows__
Most Calculated Columns use a [Standard Scalar](https://www.adaptabletools.com/docs/handbook-calculated-column-standard/index.md), basing the calculated value on other cells in the row.
However Calculated Column values can also be derived dynamically from __multiple, distinct rows__.
In this use case the Expression is of type [Aggregation](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md).
Like a Standard Scalar Expression, the Aggregated Scalar Expression returns a single scalar value.
Aggregated Scalar Expressions can accept Scalar Expressions as inputs
Each value returned is calculated by aggregating multiple rows and columns in the grid.
A Calculated Column's Aggregated Scalar Expression updates in real time when a referenced grid value changes
## Aggregation Operations
The following Aggregation operations are supported by AdapTableQL:
- `SUM`: sums the values of the specified columns
- `PERCENTAGE`: calculates the percentage of the specified columns (using `SUM` as default)
- `AVG`: calculates average of specified columns (optional `WEIGHT` parameter supports [Weighted Averages](https://www.adaptabletools.com/docs/handbook-aggregation-weighted-average/index.md))
- `MIN`: returns the minimum value of the specified columns
- `MAX`: returns the maximum value of the specified columns
- Aggregated Calculated Columns cannot be used when using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md)
- This is because they might not have all the rows on the client when performing the calculation
### Defining an Aggregated Calculated Column
There are 5 properties that you need to provide when defining an Aggregated Calculated Column:
This `ColumnId` value is used to reference the Column in AdapTable State and in other objects (e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)).
This value is used to refer to the Column in AdapTable UI.
It only needs to be provided if the `ColumnId` value is unsuitable.
The [Aggregation Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) across multiple rows.
Its wrapped inside a `Query` property under `AggregatedScalarExpression` key using one of the aggregation operations (`SUM`, `AVG`, `MIN`, `MAX`, `PERCENTAGE`).
By default an Aggregation Expression evaluates across **every** row in the grid.
Add a `GROUP_BY([column])` clause inside the expression to evaluate the aggregation against **subsets** of rows — one bucket per distinct value of the grouping column. Each row then sees the aggregated value for its own group.
In the second example, `GROUP_BY([language])` means each row receives the average watcher count for its own language.
The Data Type of the Calculated Column should be provided in `CalculatedColumnSettings`.
It is a [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) value and the object's only mandatory property. Common values are `number`, `text` or `date`.
Additional Settings for the Calculated Column (other than mandatory `DataType`) can be provided, including:
- `Filterable`
- `Pivotable`
- `Sortable`
- `Groupable`
```tsx [[1,4, "ColumnId"],[1,16, "ColumnId"],[2,5, "FriendlyName"],[2,17, "FriendlyName"],[3,7, "AggregatedScalarExpression"],[3,19, "AggregatedScalarExpression"],[4,20, "GROUP_BY"],[5,11, "DataType"],[5,23, "DataType"],[6,12, "Resizable"],[6,24, "Resizable"]]
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'sum-watchers',
FriendlyName: 'Sum Watchers',
Query: {
AggregatedScalarExpression:
'SUM([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'avg-watchers-by-lang',
FriendlyName: 'Avg Watchers by Language',
Query: {
AggregatedScalarExpression:
'AVG([github_watchers], GROUP_BY([language]))',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
],
},
```
**Example: Calculated Columns: Aggregated**
Calculated Columns: Aggregated Scalar Expressions
- This demo contains 5 Calculated Columns that use [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) - all on the `Github Watchers` Column:
- `Sum Watchers` - sums all the values
- `Average Watchers` - average of all the values
- `Min Watchers` - Minimum of the values
- `Max Watchers` - Maximum of the values
- `% Watchers` - Percentage of the values
- Note these Calculated Columns do not use grouping - see demo below for an example using Groups
### Expand to see the Aggregation Scalar Expressions
```ts
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'sum-watchers',
FriendlyName: 'Sum Watchers',
Query: { AggregatedScalarExpression: 'SUM([github_watchers])' },
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'average-watchers',
FriendlyName: 'Avg. Watchers',
Query: { AggregatedScalarExpression: 'AVG([github_watchers])' },
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'min-watchers',
FriendlyName: 'Min Watchers',
Query: { AggregatedScalarExpression: 'MIN([github_watchers])' },
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'max-watchers',
FriendlyName: 'Max Watchers',
Query: { AggregatedScalarExpression: 'MAX([github_watchers])' },
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'percentage-watchers',
FriendlyName: '% Watchers',
Query: {
AggregatedScalarExpression: 'PERCENTAGE([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
],
},
```
- Update a cell in the `Github Watchers` column and see how all 5 Calculated Columns update
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Aggregated Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
PinnedToolbars: ['Layout'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'language',
'github_watchers',
'sum-watchers',
'average-watchers',
'min-watchers',
'max-watchers',
'percentage-watchers',
'name',
],
AutoSizeColumns: true,
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'sum-watchers',
FriendlyName: 'Sum Watchers',
Query: {
AggregatedScalarExpression: 'SUM([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'average-watchers',
FriendlyName: 'Avg. Watchers',
Query: {
AggregatedScalarExpression: 'AVG([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'min-watchers',
FriendlyName: 'Min Watchers',
Query: {
AggregatedScalarExpression: 'MIN([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'max-watchers',
FriendlyName: 'Max Watchers',
Query: {
AggregatedScalarExpression: 'MAX([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
{
ColumnId: 'percentage-watchers',
FriendlyName: '% Watchers',
Query: {
AggregatedScalarExpression: 'PERCENTAGE([github_watchers])',
},
CalculatedColumnSettings: {
DataType: 'number',
Resizable: true,
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-sum-watchers',
Scope: {
ColumnIds: [
'sum-watchers',
'average-watchers',
'min-watchers',
'max-watchers',
'percentage-watchers',
],
},
Style: {
FontStyle: 'Italic',
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
### Using `GROUP_BY`
An Aggregation Scalar Function can also be applied to a **set** of rows, rather than to the entire grid.
This is done by using the `GROUP_BY` [AdapTableQL Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md).
This allows for much more powerful Expressions than displayed in the example above, becauase you can have multiple sets of Aggregations.
See the AdapTableQL Guide to [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) for more information and examples
**Example: Calculated Columns: Aggregated with GROUP_BY**
Calculated Columns: Aggregated, Grouped Scalar Expressions
- This demo contains 3 Calculated Columns that use [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md)
- All are based on the `Github Watchers` Column and all use **grouping** on the `Language` Column:
- `Sum Watchers` - sums all the values
- `Average Watchers` - average of all the values
- `% Watchers` - Percentage of the values
- It also contains another Aggregated Scalar Calculated Column - `Open/Closed Issues Percentage by Language`
- This calculates the percentage of open and closed issues of all the repos in the grid, **grouped** by language
- It's a slightly contrived example, but showcases how to calculate a percentage based on aggregated values from other columns
### Expand to see the Aggregation Scalar Expressions
```ts
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Popularity',
ColumnId: 'githubPopularity',
Query: { ScalarExpression: '[github_watchers] + [github_stars]' },
},
{
FriendlyName: 'Subscribers Ratio',
ColumnId: 'subscribersRatio',
Query: { AggregatedScalarExpression: 'PERCENTAGE([github_watchers])', },
},
{
ColumnId: 'average-popularity-by-lang',
FriendlyName: 'Avg. Popularity by Lang',
Query: { AggregatedScalarExpression: 'AVG([githubPopularity], GROUP_BY([language]))', },
CalculatedColumnSettings: { DataType: 'number' },
},
{
ColumnId: 'percentage-issues-by-lang',
FriendlyName: 'Open/Closed Issues % by Lang',
Query: { AggregatedScalarExpression: 'PERCENTAGE([open_issues_count], SUM([closed_issues_count], GROUP_BY([language]))) ', },
CalculatedColumnSettings: { DataType: 'number' },
},
],
},
```
- Update a cell in the `Github Watchers` column and see how the Calculated Columns update
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Aggregated GroupBy Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
PinnedToolbars: ['Layout'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'language',
'github_watchers',
'sum-watchers-by-lang',
'avg-watchers-by-lang',
'percentage-watchers-by-lang',
'percentage-issues-by-lang',
'name',
],
},
{
Name: 'Grouped',
TableColumns: [
'language',
'github_watchers',
'sum-watchers-by-lang',
'avg-watchers-by-lang',
'percentage-watchers-by-lang',
'percentage-issues-by-lang',
'name',
],
RowGroupedColumns: ['language'],
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'sum-watchers-by-lang',
FriendlyName: 'Sum Watchers by Lang',
Query: {
AggregatedScalarExpression:
'SUM([github_watchers], GROUP_BY([language])) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'avg-watchers-by-lang',
FriendlyName: 'Avg Watchers by Lang',
Query: {
AggregatedScalarExpression:
'AVG([github_watchers], GROUP_BY([language])) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'percentage-watchers-by-lang',
FriendlyName: '% Watchers by Lang',
Query: {
AggregatedScalarExpression:
'PERCENTAGE([github_watchers], SUM([github_watchers], GROUP_BY([language]))) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'percentage-issues-by-lang',
FriendlyName: 'Open/Closed Issues % by Lang',
Query: {
AggregatedScalarExpression:
'PERCENTAGE([open_issues_count], SUM([closed_issues_count], GROUP_BY([language]))) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-sum-watchers-by-lang',
Scope: {
ColumnIds: [
'sum-watchers-by-lang',
'avg-watchers-by-lang',
'percentage-watchers-by-lang',
'percentage-issues-by-lang',
],
},
Style: {
FontStyle: 'Italic',
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
## Grouped Rows
The values in Aggregation Calculated Columns can be used when summarising data for [Grouped Rows](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md).
AdapTable will ensure that if the Grid contains Aggregated Calculated Columns and Grouped Rows, the "aggFunc" summaries will display normally.
### A note on terminology
The terminology here can be confusing because "Aggregation" and "Grouping" can mean different things by AG Grid and AdapTable depending on the context.
**Grouping**
- AdapTable here uses Grouping to describe how it performs the Aggregation Scalar calculation on different sets of rows by using the `GROUP_BY` keyword
- AG Grid uses Grouping to mean when it visually groups the rows using [Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md)
**Aggregation**
- AdapTable uses it to describe the calculation performed on multiple rows to evaluate Calculated Column Cells
- AG Grid uses the term (also known as 'aggfunc') to mean the the "summary" data displayed in Grouped Rows
**Example: Calculated Columns: Aggregated with Row Grouping**
Calculated Columns: Aggregated Scalar Expressions in Row Groups
- This demo contains 4 Calculated Columns that use [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) based on the `Github Watchers` Column
- Like in the demo above all the Aggregated Scalar Expressions use `GROUP_BY` on the `Language` Column
- We have also created a Layout which contains [Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) on the Language Column
- The Layout also contains 4 AG Grid `aggFunc` summaries each connected to an AdapTable Aggregated Expression:
- `SumByLang` - uses a `SUM` AdapTable Aggregated Expression and a `sum` AG Grid aggFunc
- `AvgByLang` - uses a `AVG` AdapTable Aggregated Expression and a `avg` AG Grid aggFunc
- `MinByLang` - uses a `MIN` AdapTable Aggregated Expression and a `min` AG Grid aggFunc
- `MaxByLang` - uses a `MAX` AdapTable Aggregated Expression and a `max` AG Grid aggFunc
- We have created an [AG Grid Column Group](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md) to display the 4 Calculated Columns as a set
- Update a cell in the `Github Watchers` Column and note how the 4 Calculated Columns update and so does the AG Grid agg summary
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Aggregated Row Grouped Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
PinnedToolbars: ['Layout'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Grouped',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'language',
'github_watchers',
'sum-watchers-by-lang',
'avg-watchers-by-lang',
'min-watchers-by-lang',
'max-watchers-by-lang',
'name',
],
},
{
Name: 'Grouped',
TableColumns: [
'name',
'github_watchers',
'sum-watchers-by-lang',
'avg-watchers-by-lang',
'min-watchers-by-lang',
'max-watchers-by-lang',
],
RowGroupedColumns: ['language'],
SuppressAggFuncInHeader: true,
TableAggregationColumns: [
{
ColumnId: 'sum-watchers-by-lang',
AggFunc: 'sum',
},
{
ColumnId: 'avg-watchers-by-lang',
AggFunc: 'avg',
},
{
ColumnId: 'min-watchers-by-lang',
AggFunc: 'min',
},
{
ColumnId: 'max-watchers-by-lang',
AggFunc: 'max',
},
],
ColumnSizing: {
name: {Width: 100},
github_watchers: {Width: 150},
'sum-watchers-by-lang': {Width: 100},
'avg-watchers-by-lang': {Width: 100},
'min-watchers-by-lang': {Width: 100},
'max-watchers-by-lang': {Width: 100},
},
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'sum-watchers-by-lang',
FriendlyName: 'Sum',
Query: {
AggregatedScalarExpression:
'SUM([github_watchers], GROUP_BY([language])) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'avg-watchers-by-lang',
FriendlyName: 'Avg',
Query: {
AggregatedScalarExpression:
'AVG([github_watchers], GROUP_BY([language])) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'min-watchers-by-lang',
FriendlyName: 'Min',
Query: {
AggregatedScalarExpression:
'MIN([github_watchers], GROUP_BY([language])) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'max-watchers-by-lang',
FriendlyName: 'Max',
Query: {
AggregatedScalarExpression:
'MAX([github_watchers], GROUP_BY([language])) ',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-sum-watchers-by-lang',
Scope: {
ColumnIds: [
'sum-watchers-by-lang',
'avg-watchers-by-lang',
'min-watchers-by-lang',
'max-issues-by-lang',
],
},
Style: {
FontStyle: 'Italic',
},
},
{
Name: 'formatColumn-avg-watchers-by-lang',
Scope: {
ColumnIds: ['avg-watchers-by-lang'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
```ts
import {ColDef, ColGroupDef} from 'ag-grid-enterprise';
export const columnDefs: (ColDef | ColGroupDef)[] = [
{
field: 'name',
cellDataType: 'text',
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
headerName: 'Github Watchers Aggregations (Grouped by Language)',
marryChildren: true,
children: [
{
field: 'sum-watchers-by-lang',
headerName: 'Sum',
type: ['calculatedColumn'],
cellDataType: 'number',
},
{
field: 'avg-watchers-by-lang',
headerName: 'Avg',
type: ['calculatedColumn'],
cellDataType: 'number',
},
{
field: 'min-watchers-by-lang',
headerName: 'Min',
type: ['calculatedColumn'],
cellDataType: 'number',
},
{
field: 'max-watchers-by-lang',
headerName: 'Max',
type: ['calculatedColumn'],
cellDataType: 'number',
},
],
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
columnGroupShow: 'closed',
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
columnGroupShow: 'closed',
},
{
field: 'license',
cellDataType: 'text',
editable: false,
enablePivot: true,
enableRowGroup: true,
},
{field: 'has_wiki', headerName: 'Has Wiki', cellDataType: 'boolean'},
{
field: 'has_projects',
headerName: 'Has Projects',
cellDataType: 'boolean',
},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'description',
cellDataType: 'text',
sortable: false,
columnGroupShow: 'closed',
},
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
];
```
---
# Configuring Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-configuring
- Calculated Columns can be provided by developers through Calculated Column Initial State
- The definition includes an Id, the Column's Expression and any associated behaviour
## AG Grid Definitions
Calculated columns are typically **not** provided in the `ColDefs` property in AG Grid GridOptions.
Instead, the definition provided in Initial State suffices for AdapTable to be able to create the associated AG Grid column automatically.
However sometimes a developer might want to add an AG Grid element to the column.
For instance a tooltip might be needed, or there might be a requirement to put the Calculated Column inside a Column Group (which is an AG Grid feature).
This is possible: a column can be provided in AG Grid ColDefs but by specifying a [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) of `calculatedColumn`, AdapTable will automatically wire it up with an associated Calculated Column definition.
- Set the [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) to be `calculatedColumn`
- The `ColId` in the Column Definition and `ColumnId` in the Calculated Column definition must be the same value
**Example: Calculated Columns: Defining in AG Grid**
Calculated Columns: Adding AG Grid properties
- This demo contains an AG Grid Column Group - `Github Averages`
- The group contains 2 Calculated Columns `Github Avg By Language` and `Github Avg By Licence`
- Both the [Column Group](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md) and the 2 containing Columns were defined in AG Grid Column Defs
- The 2 columns in the Group were given AG Grid Header and Cell ToolTips
- They were also given a type of `calculatedColumn` which is what allowed AdapTable to wire everything together
- Hover over a cell in the Calculated Column and see the Tooltip which AG Grid provides
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Defining Calculated Columns in AG Grid',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'FormatColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'github_stars',
'license',
'language',
'starsAvgByLanguage',
'starsAvgByLicence',
'github_watchers',
],
Name: 'Standard Layout',
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'starsAvgByLanguage',
Query: {
AggregatedScalarExpression:
'AVG([github_stars] ,GROUP_BY([language] ) ) ',
},
FriendlyName: 'Github Avg By Language',
CalculatedColumnSettings: {DataType: 'number'},
},
{
ColumnId: 'starsAvgByLicence',
Query: {
AggregatedScalarExpression:
'AVG([github_stars] ,GROUP_BY([license] ) ) ',
},
FriendlyName: 'Github Avg By Licence',
CalculatedColumnSettings: {DataType: 'number'},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-starsAvgByLanguage',
Scope: {
ColumnIds: ['starsAvgByLanguage', 'starsAvgByLicence'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
```ts
import {ColDef, ColGroupDef, ITooltipParams} from 'ag-grid-enterprise';
export const columnDefs: (ColDef | ColGroupDef)[] = [
{
field: 'name',
cellDataType: 'text',
sortable: true,
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
field: 'license',
cellDataType: 'text',
editable: false,
enablePivot: true,
enableRowGroup: true,
},
{
headerName: 'Github Averages',
children: [
{
colId: 'starsAvgByLanguage',
type: ['calculatedColumn'],
cellDataType: 'number',
headerTooltip:
"Shows all the Github Stars for the framework's language",
tooltipValueGetter: (params: ITooltipParams) => {
return 'All Stars for ' + params.data.language;
},
},
{
colId: 'starsAvgByLicence',
type: ['calculatedColumn'],
cellDataType: 'number',
headerTooltip: "Shows all the Github Stars for the framework's licence",
tooltipValueGetter: (params: ITooltipParams) => {
return 'All Stars for ' + params.data.license;
},
},
],
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{
field: 'has_wiki',
headerName: 'Has Wiki',
cellDataType: 'boolean',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
];
```
See [Adding Column Types for Special Columns](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md) for more details and a demo
---
# Cumulative Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-cumulative
- Cumulative Calculated Columns perform cumulative aggregations
- The aggregation operation is applied to each row cumulatively in a specific, given order
Calculated Columns are able to display [Cumulative Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md).
These are an advanced form of [Aggregation Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md).
They are similar in that the values derive from multiple rows but with one fundamental difference: they perform that perform __cumulative aggregations__.
This means that the aggregation operation (e.g., `SUM`, `MIN`, `MAX`) is applied to each row __cumulatively__ in a specific, given order.
This is particularly useful, for example, when we want to calculate a Running Total of a column
### Defining a Cumulative Calculated Column
There are 5 properties that you need to provide when defining a Cumulative Calculated Column:
This `ColumnId` value is used to reference the Column in AdapTable State and in other objects (e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)).
This value is used to refer to the Column in AdapTable UI.
It only needs to be provided if the `ColumnId` value is unsuitable.
This is a [Cumulative Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md) evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) cumulatively across the grid in a specified order.
It is wrapped inside a `Query` property under the `AggregatedScalarExpression` key and uses the `CUMUL` function with an inner aggregation (`SUM`, `MIN`, `MAX`, etc.) and an `OVER` clause that sets the ordering.
The Data Type of the Calculated Column should be provided in `CalculatedColumnSettings`.
It is a [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) value and the object's only mandatory property. Common values are `number`, `text` or `date`.
Additional Settings for the Calculated Column (other than mandatory `DataType`) can be provided, including:
- `Filterable`
- `Pivotable`
- `Sortable`
- `Groupable`
```tsx [[1,4, "ColumnId"],[1,16, "ColumnId"],[2,5, "FriendlyName"],[2,17, "FriendlyName"],[3,7, "AggregatedScalarExpression"],[3,19, "AggregatedScalarExpression"],[4,11, "DataType"],[4,23, "DataType"],[5,12, "Filterable"],[5,24, "Sortable"]]
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'cumulated-stars-count',
FriendlyName: 'Cumulated Stars Count',
Query: {
AggregatedScalarExpression:
'CUMUL( SUM([github_stars]), OVER([created_at]) )',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
},
},
{
ColumnId: 'max-tech-debt-over-stars',
FriendlyName: 'Maximum Technical Debt',
Query: {
AggregatedScalarExpression:
'CUMUL( MAX([open_issues_count]), OVER([github_stars]) )',
},
CalculatedColumnSettings: {
DataType: 'number',
Sortable: true,
},
},
],
},
```
**Example: Calculated Columns: Cumulative**
Calculated Columns: Cumulative Aggregated Expressions
- This demo contains 2 Calculated Columns that use [Cumulative Aggregation Scalar Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-cumulative/index.md):
- `Cumulated Stars Count` - displays the cumulative sum of stars count of all repos in the grid, aggregated over the `Created` date
- `Maximum Technical Debt` - shows the cumulative maxima of open issues of all repos in the grid, aggregated over the `GitHub Stars` count
- The Calculated Columns are formatted using [Column Formatting](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md).
### Expand to see the Cumulative Aggregation Scalar Expressions
```ts
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'cumulated-stars-count',
FriendlyName: 'Cumulated Stars Count',
Query: {
AggregatedScalarExpression:
'CUMUL( SUM([github_stars]), OVER([created_at]) )',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'max-tech-debt-over-stars',
FriendlyName: 'Maximum Technical Debt',
Query: {
AggregatedScalarExpression:
'CUMUL( MAX([open_issues_count]), OVER([github_stars]) )',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Cumulative Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'created_at',
'github_stars',
'open_issues_count',
'cumulated-stars-count',
'max-tech-debt-over-stars',
],
ColumnSorts: [{ColumnId: 'created_at', SortOrder: 'Asc'}],
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'cumulated-stars-count',
FriendlyName: 'Cumulated Stars Count',
Query: {
AggregatedScalarExpression:
'CUMUL( SUM([github_stars]), OVER([created_at]) )',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'max-tech-debt-over-stars',
FriendlyName: 'Maximum Technical Debt',
Query: {
AggregatedScalarExpression:
'CUMUL( MAX([open_issues_count]), OVER([github_stars]) )',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-created_at',
Scope: {
ColumnIds: ['created_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'yyyy/MM/dd',
},
},
},
],
},
},
};
```
---
# Quantile Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-quantile
- Quantile Calculated Columns allow 'buckets' of values to be created
- Each cell is placed into a specific bucket based on its value relative to others in the group
Calculated Columns are able to display [Quantile Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md).
These are an advanced form of [Aggregation Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-aggregation/index.md) that perform __quantile aggregations__.
The Calculated Colunn is evaluated by placing each cell's value into a different bucket based on its value relative to others in the group.
Quantile Aggregation leverage the `QUANT` Expression Function.
This receives a value to evaluate (typically a column name) and the number of buckets to create.
### Defining a Quantile Calculated Column
There are 5 properties that you need to provide when defining a Quantile Calculated Column:
This `ColumnId` value is used to reference the Column in AdapTable State and in other objects (e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)).
This value is used to refer to the Column in AdapTable UI.
It only needs to be provided if the `ColumnId` value is unsuitable.
This is a [Quantile Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md) evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) by placing each row's value into a bucket relative to other rows.
It is wrapped inside a `Query` property under the `AggregatedScalarExpression` key and uses the `QUANT` function — a column reference, a number of buckets, and optionally a `GROUP_BY` clause.
The Data Type of the Calculated Column should be provided in `CalculatedColumnSettings`.
It is a [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) value and the object's only mandatory property. Common values are `number`, `text` or `date`.
Additional Settings for the Calculated Column (other than mandatory `DataType`) can be provided, including:
- `Filterable`
- `Pivotable`
- `Sortable`
- `Groupable`
```tsx [[1,4, "ColumnId"],[1,16, "ColumnId"],[2,5, "FriendlyName"],[2,17, "FriendlyName"],[3,7, "AggregatedScalarExpression"],[3,19, "AggregatedScalarExpression"],[4,11, "DataType"],[4,23, "DataType"],[5,12, "Filterable"],[5,24, "Sortable"]]
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'quartile',
FriendlyName: 'Quartile',
Query: {
AggregatedScalarExpression:
'QUANT([value], 4)',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
},
},
{
ColumnId: 'quartile-by-type',
FriendlyName: 'Quartile by Type',
Query: {
AggregatedScalarExpression:
'QUANT([value], 4, GROUP_BY([type]))',
},
CalculatedColumnSettings: {
DataType: 'number',
Sortable: true,
},
},
],
},
```
**Example: Quantile Calculated Columns**
Calculated Columns: Quantile Aggregations
- This Example demonstrates how to use the `QUANT` Expression Function to calculate Quantile functions
- It contains 100 Tickers each with a `Value` and a `Type`
- The provided Value is from 1 to 100 in ascending order (in order to demonstrate how Quantiles work)
- 4 Calculated Columns are provided in the Initial Adaptable State - each using `QUANT`:
- `Quartile` - divides the 100 Ticker Values into 4 groups
- `Quintile` - divides the 100 Ticker Values into 5 groups
- `Decile` - divides the 100 Ticker Values into 10 groups
- `Percentile` - divides the 100 Ticker Values into 100 groups (so there is therefore just 1 value per group)
- A 5th Calculated Column illustrates how to group Quantiles by levering the `GROUP_BY` keyword:
- `Grouped by Type` - creates 3 bucket for each set of Values in each group of a distinct 'Type' (with a [Column Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md))
- Sort the Grid by *Type* to see how the `Grouped by Type` column creates 3 buckets for each dinstinct Type
- Change some Values and note how this changes all the Quantiles it is placed in
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'Id',
adaptableId: 'Quantile Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'Id',
'Ticker',
'Value',
'Type',
'Quartile',
'Quintile',
'Decile',
'Percentile',
'TypeGroup',
],
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'Quartile',
Query: {
AggregatedScalarExpression: 'QUANT([Value], 4)',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'Quintile',
Query: {
AggregatedScalarExpression: 'QUANT([Value], 5)',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'Decile',
Query: {
AggregatedScalarExpression: 'QUANT([Value], 10)',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'Percentile',
Query: {
AggregatedScalarExpression: 'QUANT([Value], 100)',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
ColumnId: 'TypeGroup',
Query: {
AggregatedScalarExpression: 'QUANT([Value], 3, GROUP_BY([Type]))',
},
FriendlyName: 'Grouped by Type',
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-TypeGroup',
Scope: {
ColumnIds: ['TypeGroup'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Prefix: 'Bucket: ',
},
},
},
],
},
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
headerName: 'Id',
field: 'Id',
filter: true,
editable: false,
sortable: true,
cellDataType: 'number',
},
{
headerName: 'Value',
field: 'Value',
filter: true,
editable: true,
sortable: true,
cellDataType: 'number',
},
{
headerName: 'Ticker',
field: 'Ticker',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Type',
field: 'Type',
filter: true,
editable: true,
sortable: true,
cellDataType: 'text',
},
];
```
```ts
export const rowData = [
{
Ticker: 'AAL',
Value: 1,
Id: 1,
Type: 'Transport',
},
{
Ticker: 'AAPL',
Value: 2,
Id: 2,
Type: 'IT',
},
{
Ticker: 'AB',
Value: 3,
Id: 3,
Type: 'Finance',
},
{
Ticker: 'ABBV',
Value: 4,
Id: 4,
Type: 'Manufacturing',
},
{
Ticker: 'ACER',
Value: 5,
Id: 5,
Type: 'Other',
},
{
Ticker: 'ACN',
Value: 6,
Id: 6,
Type: 'IT',
},
{
Ticker: 'ADI',
Value: 7,
Id: 7,
Type: 'Manufacturing',
},
{
Ticker: 'AEG',
Value: 8,
Id: 8,
Type: 'Finance',
},
{
Ticker: 'AMZN',
Value: 9,
Id: 9,
Type: 'Consumer',
},
{
Ticker: 'BA',
Value: 10,
Id: 10,
Type: 'Transport',
},
{
Ticker: 'BAC',
Value: 11,
Id: 11,
Type: 'Finance',
},
{
Ticker: 'BAH',
Value: 12,
Id: 12,
Type: 'IT',
},
{
Ticker: 'BB',
Value: 13,
Id: 13,
Type: 'IT',
},
{
Ticker: 'BBDC',
Value: 14,
Id: 14,
Type: 'Finance',
},
{
Ticker: 'BBIG',
Value: 15,
Id: 15,
Type: 'Consumer',
},
{
Ticker: 'BBQ',
Value: 16,
Id: 16,
Type: 'Consumer',
},
{
Ticker: 'BCS',
Value: 17,
Id: 17,
Type: 'Finance',
},
{
Ticker: 'BK',
Value: 18,
Id: 18,
Type: 'Finance',
},
{
Ticker: 'C',
Value: 19,
Id: 19,
Type: 'Finance',
},
{
Ticker: 'CAJ',
Value: 20,
Id: 20,
Type: 'IT',
},
{
Ticker: 'CALX',
Value: 21,
Id: 21,
Type: 'IT',
},
{
Ticker: 'CASH',
Value: 22,
Id: 22,
Type: 'Finance',
},
{
Ticker: 'CBAT',
Value: 23,
Id: 23,
Type: 'Manufacturing',
},
{
Ticker: 'CBIO',
Value: 24,
Id: 24,
Type: 'Manufacturing',
},
{
Ticker: 'CCAP',
Value: 25,
Id: 25,
Type: 'Finance',
},
{
Ticker: 'CCL',
Value: 26,
Id: 26,
Type: 'Consumer',
},
{
Ticker: 'CDR',
Value: 27,
Id: 27,
Type: 'Finance',
},
{
Ticker: 'CDTX',
Value: 28,
Id: 28,
Type: 'Manufacturing',
},
{
Ticker: 'CSCO',
Value: 29,
Id: 29,
Type: 'IT',
},
{
Ticker: 'DAL',
Value: 30,
Id: 30,
Type: 'Transport',
},
{
Ticker: 'DAO',
Value: 31,
Id: 31,
Type: 'Consumer',
},
{
Ticker: 'DAVA',
Value: 32,
Id: 32,
Type: 'IT',
},
{
Ticker: 'DB',
Value: 33,
Id: 33,
Type: 'Finance',
},
{
Ticker: 'DBRG',
Value: 34,
Id: 34,
Type: 'Other',
},
{
Ticker: 'DBX',
Value: 35,
Id: 35,
Type: 'IT',
},
{
Ticker: 'DCI',
Value: 36,
Id: 36,
Type: 'Manufacturing',
},
{
Ticker: 'DD',
Value: 37,
Id: 37,
Type: 'Manufacturing',
},
{
Ticker: 'DELL',
Value: 38,
Id: 38,
Type: 'IT',
},
{
Ticker: 'DEO',
Value: 39,
Id: 39,
Type: 'Consumer',
},
{
Ticker: 'DHBC',
Value: 40,
Id: 40,
Type: 'Other',
},
{
Ticker: 'DOW',
Value: 41,
Id: 41,
Type: 'Manufacturing',
},
{
Ticker: 'EVA',
Value: 42,
Id: 42,
Type: 'Manufacturing',
},
{
Ticker: 'EVGN',
Value: 43,
Id: 43,
Type: 'Manufacturing',
},
{
Ticker: 'EVH',
Value: 44,
Id: 44,
Type: 'Other',
},
{
Ticker: 'EVTC',
Value: 45,
Id: 45,
Type: 'IT',
},
{
Ticker: 'EZGO',
Value: 46,
Id: 46,
Type: 'Transport',
},
{
Ticker: 'F',
Value: 47,
Id: 47,
Type: 'Transport',
},
{
Ticker: 'FBP',
Value: 48,
Id: 48,
Type: 'Finance',
},
{
Ticker: 'FCBC',
Value: 49,
Id: 49,
Type: 'Finance',
},
{
Ticker: 'FDP',
Value: 50,
Id: 50,
Type: 'Consumer',
},
{
Ticker: 'FDS',
Value: 51,
Id: 51,
Type: 'Finance',
},
{
Ticker: 'FEMY',
Value: 52,
Id: 52,
Type: 'Other',
},
{
Ticker: 'FSP',
Value: 53,
Id: 53,
Type: 'Finance',
},
{
Ticker: 'GACQ',
Value: 54,
Id: 54,
Type: 'Other',
},
{
Ticker: 'GATX',
Value: 55,
Id: 55,
Type: 'Finance',
},
{
Ticker: 'GB',
Value: 56,
Id: 56,
Type: 'IT',
},
{
Ticker: 'GBR',
Value: 57,
Id: 57,
Type: 'Manufacturing',
},
{
Ticker: 'GCI',
Value: 58,
Id: 58,
Type: 'Other',
},
{
Ticker: 'GDDY',
Value: 59,
Id: 59,
Type: 'IT',
},
{
Ticker: 'GEO',
Value: 60,
Id: 60,
Type: 'Finance',
},
{
Ticker: 'GOOG',
Value: 61,
Id: 61,
Type: 'Consumer',
},
{
Ticker: 'HCP',
Value: 62,
Id: 62,
Type: 'IT',
},
{
Ticker: 'HEP',
Value: 63,
Id: 63,
Type: 'Manufacturing',
},
{
Ticker: 'HLGN',
Value: 64,
Id: 64,
Type: 'Manufacturing',
},
{
Ticker: 'HUM',
Value: 65,
Id: 65,
Type: 'Other',
},
{
Ticker: 'IBM',
Value: 66,
Id: 66,
Type: 'IT',
},
{
Ticker: 'ICE',
Value: 67,
Id: 67,
Type: 'Finance',
},
{
Ticker: 'JEF',
Value: 68,
Id: 68,
Type: 'Finance',
},
{
Ticker: 'JPM',
Value: 69,
Id: 69,
Type: 'Finance',
},
{
Ticker: 'KRO',
Value: 70,
Id: 70,
Type: 'Manufacturing',
},
{
Ticker: 'KTB',
Value: 71,
Id: 71,
Type: 'Consumer',
},
{
Ticker: 'LUMN',
Value: 72,
Id: 72,
Type: 'IT',
},
{
Ticker: 'LVO',
Value: 73,
Id: 73,
Type: 'Consumer',
},
{
Ticker: 'LX',
Value: 74,
Id: 74,
Type: 'Consumer',
},
{
Ticker: 'MAN',
Value: 75,
Id: 75,
Type: 'Other',
},
{
Ticker: 'MBI',
Value: 76,
Id: 76,
Type: 'Finance',
},
{
Ticker: 'MIT',
Value: 77,
Id: 77,
Type: 'Other',
},
{
Ticker: 'MSFT',
Value: 78,
Id: 78,
Type: 'IT',
},
{
Ticker: 'NDAQ',
Value: 79,
Id: 79,
Type: 'Finance',
},
{
Ticker: 'NE',
Value: 80,
Id: 80,
Type: 'Manufacturing',
},
{
Ticker: 'NGG',
Value: 81,
Id: 81,
Type: 'Manufacturing',
},
{
Ticker: 'NKE',
Value: 82,
Id: 82,
Type: 'Consumer',
},
{
Ticker: 'OGE',
Value: 83,
Id: 83,
Type: 'Manufacturing',
},
{
Ticker: 'ORCL',
Value: 84,
Id: 84,
Type: 'IT',
},
{
Ticker: 'PAFO',
Value: 85,
Id: 85,
Type: 'Other',
},
{
Ticker: 'PAYX',
Value: 86,
Id: 86,
Type: 'IT',
},
{
Ticker: 'PCSB',
Value: 87,
Id: 87,
Type: 'Finance',
},
{
Ticker: 'PEP',
Value: 88,
Id: 88,
Type: 'Consumer',
},
{
Ticker: 'SBUX',
Value: 89,
Id: 89,
Type: 'Consumer',
},
{
Ticker: 'SCS',
Value: 90,
Id: 90,
Type: 'Other',
},
{
Ticker: 'SENEA',
Value: 91,
Id: 91,
Type: 'Consumer',
},
{
Ticker: 'SIF',
Value: 92,
Id: 92,
Type: 'Transport',
},
{
Ticker: 'TM',
Value: 93,
Id: 93,
Type: 'Transport',
},
{
Ticker: 'TNK',
Value: 94,
Id: 94,
Type: 'Manufacturing',
},
{
Ticker: 'TSLA',
Value: 95,
Id: 95,
Type: 'Transport',
},
{
Ticker: 'USB',
Value: 96,
Id: 96,
Type: 'Finance',
},
{
Ticker: 'VCEL',
Value: 97,
Id: 97,
Type: 'Manufacturing',
},
{
Ticker: 'WMT',
Value: 98,
Id: 98,
Type: 'Consumer',
},
{
Ticker: 'YNDX',
Value: 99,
Id: 99,
Type: 'Consumer',
},
{
Ticker: 'ZYXI',
Value: 100,
Id: 100,
Type: 'Other',
},
];
```
See [Quantile Aggregation Scalar Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-quantile/index.md) for more information
---
# Referencing Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-referencing
- Once created a Calculated Column can be used and managed like any other Column in AG Grid
- Calculated Columns can also be referenced in AG Grid Charts
Calculated Columns are treated like any other AdapTable (or AG Grid) Column.
Accordingly, a Calculated Column's Expression can reference other Calculated Columns in the Grid if required.
- There is no limitation on how many Calculated Columns are chained - [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) will evaluate each in turn
- However at some point performance might be impacted if you have a large chain with complicated calculations
**Example: Calculated Columns: Referencing**
Calculated Columns: Reference other Calc Cols
- This demo contains 3 Calculated Columns, one of which is evaluated based on the other 2
- `Issues Open/Total Ratio` - shows ratio between open and total number of issues
- `PR Open/Total Ratio` - shows ratio between open and total number of pull-requests
- `Score` - is calculated by computing the average value of the previous 2 ratio Calculated Columns (a higher score is better)
- Change a value in `Open Issues` or `Closed Issues` and see how the `Score` Calculated Column also updates
- Change `Score` to take the maximum value between 'Issues Open/Total Ratio' and 'PR Open/Total Ratio'
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Referencing Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'open_issues_count',
'closed_issues_count',
'open-total-issue-ratio',
'open-total-pr-ratio',
'score',
'licence',
'created_at',
'github_stars',
],
Name: 'Standard Layout',
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Issues Open/Total Ratio',
ColumnId: 'open-total-issue-ratio',
Query: {
ScalarExpression:
'[open_issues_count] / ([open_issues_count] +[closed_issues_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'PR Open/Total Ratio',
ColumnId: 'open-total-pr-ratio',
Query: {
ScalarExpression:
'[open_pr_count] / ([open_pr_count] + [closed_pr_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Score',
ColumnId: 'score',
Query: {
ScalarExpression:
'AVG([open-total-pr-ratio], [open-total-issue-ratio]) * 100',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatC olumn-open-total-issue-ratio',
Scope: {
ColumnIds: [
'open-total-issue-ratio',
'open-total-pr-ratio',
'score',
],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
## Flashing Calculated Columns
Since [Version 23.0](https://www.adaptabletools.com/support/version-230-release-note) Calculated Columns can [flash their cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) when their contents change.
Calculated Columns are not directly editable but they will update if a referenced column's value changes
It is possible for one Calculated Column to reference another Calculated Column and still flash when changed.
**Example: Calculated Columns: Flashing**
Calculated Columns flash when a referenced column changes
- This example shows 2 Calculated Columns which flash when values in their referenced columns change:
- `Total Stars + Watchers` has an **`ANY_CHANGE()`** rule and flashes when one of its referenced Columns (`Github Stars` and `Github Watchers`) tick
- `Stars Index (÷ 1000)` references the first Calculated Column with a rule **`[stars-index] > 50`**, so the chained column flashes when its value changes (and the rule matches)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Calculated Column Flashing',
flashingCellOptions: {
defaultFlashDuration: 600,
defaultUpChangeStyle: {
BackColor: '#86d586',
},
defaultDownChangeStyle: {
BackColor: '#e18989',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'FlashingCell'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
AutoSizeColumns: true,
TableColumns: [
'name',
'github_stars',
'github_watchers',
'total-stars-watchers',
'stars-index',
],
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Total Stars + Watchers',
ColumnId: 'total-stars-watchers',
Query: {
ScalarExpression: '[github_stars] + [github_watchers]',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Stars Index (÷ 1000)',
ColumnId: 'stars-index',
Query: {
ScalarExpression: '[total-stars-watchers] / 1000',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FlashingCell: {
FlashingCellDefinitions: [
{
Name: 'flash-total-stars-watchers',
Scope: {
ColumnIds: ['total-stars-watchers'],
},
Rule: {
BooleanExpression: 'ANY_CHANGE()',
},
},
{
Name: 'flash-stars-index-high',
Scope: {
ColumnIds: ['stars-index'],
},
Rule: {
BooleanExpression: '[stars-index] > 50',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'format-calc-columns',
Scope: {
ColumnIds: ['total-stars-watchers', 'stars-index'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 0,
},
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
import {tickNumericData} from 'tickingDataHelper';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
tickNumericData(adaptableApi, 400, ['github_stars', 'github_watchers']);
};
```
## Calculated Columns and Alerts
Calculated Columns (also since [Version 23.0](https://www.adaptabletools.com/support/version-230-release-note)) can trigger [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md).
This is most commonly a [Data Change Alert](https://www.adaptabletools.com/docs/handbook-alerting-data-change/index.md) with a [Boolean Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) evaluated against the changed cell value
Similar to Flashing Cells its possible for one Calculated Column to reference another Calculated Column and still trigger the Alert.
**Example: Calculated Columns: Alerts**
Data Change Alerts on Calculated Columns
- This example shows 2 Calculated Columns which trigger Data Change Alerts when values in their referenced columns change:
- `Total Stars + Watchers` triggers an Alert (with a Notification) using the rule **`[total-stars-watchers] > 200000`**
- `Stars Index (÷ 1000)` references the first Calculated Column and a second Alert uses the rule **`[stars-index] > 150`** on that chained column
- Watch notifications appear when **`github_stars`** or **`github_watchers`** tick and their calculated values satisfy the Alert rules
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Calculated Column Alerts',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'Alert'],
Tabs: [
{
Name: 'Toolbars',
Toolbars: ['Alert'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Alert'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
AutoSizeColumns: true,
TableColumns: [
'name',
'github_stars',
'github_watchers',
'total-stars-watchers',
'stars-index',
],
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Total Stars + Watchers',
ColumnId: 'total-stars-watchers',
Query: {
ScalarExpression: '[github_stars] + [github_watchers]',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Stars Index (÷ 1000)',
ColumnId: 'stars-index',
Query: {
ScalarExpression: '[total-stars-watchers] / 1000',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
Alert: {
AlertDefinitions: [
{
Name: 'High total stars + watchers',
MessageType: 'Warning',
MessageHeader: 'High engagement',
MessageText: 'Combined stars and watchers exceeded 200,000',
Scope: {
ColumnIds: ['total-stars-watchers'],
},
Rule: {
BooleanExpression: '[total-stars-watchers] > 200000',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
{
Name: 'High stars index',
MessageType: 'Info',
MessageHeader: 'Stars index',
MessageText: 'Chained calculated value is above 150',
Scope: {
ColumnIds: ['stars-index'],
},
Rule: {
BooleanExpression: '[stars-index] > 150',
},
AlertProperties: {
DisplayNotification: true,
HighlightCell: true,
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'format-calc-columns',
Scope: {
ColumnIds: ['total-stars-watchers', 'stars-index'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 0,
},
},
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
import {tickNumericData} from 'tickingDataHelper';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
tickNumericData(adaptableApi, 500, ['github_stars', 'github_watchers']);
};
```
### Recalculating Dependent Calculated Columns
Flashing and Alerting in Calculated Columns is made possible as follows:
When a source column changes, AdapTable recalculates any dependent Calculated Columns and emits a synthetic **`calculatedColumnChange`** event for each derived value that actually moved.
This means that any objects scoped to a Calculated Column (e.g. [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md) or [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md)) can react when a column **referenced in its Expression** is edited or ticked.
This happens even though the Calculated Column itself, by its very nature, is not editable.
## Calculated Columns in Charts
As "normal" Columns, Calculated Columns can also be referenced in [Charts](https://www.adaptabletools.com/docs/handbook-charts/index.md).
If a Chart contains a Calculated Column, then any changes to a Column which is referenced in the Calculated Columns's Expression, will cause the chart to re-render.
**Example: Charts Calculated Column**
Charts using Calculated Columns
- This example demonstrates how Calculated Columns can be used in [Charts](https://www.adaptabletools.com/docs/handbook-charts/index.md)
- We create a Calculated Column called `Total PRs` which sums the `Open PRs` and `Closed PRs` columns
- We then create a small Pie Chart which displays the names of the first 5 frameworks and the Total PRs
- Any change to the underlying value of one of the Calculated Column Expression's constituent columns will cause the Chart to redraw
- Set the `Open PRs` Column in the first row (for Vue) to be 22400 and see how the Chart changes
```ts
import {
AdaptableButton,
AdaptableOptions,
CellUpdateRequest,
CustomToolbarButtonContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Charts for Calculated Columns',
dashboardOptions: {
customToolbars: [
{
name: 'ButtonToolbar',
title: 'Buttons',
toolbarButtons: [
{
label: 'Update First Row',
onClick: (
button: AdaptableButton,
context: CustomToolbarButtonContext
) => {
const firstNode = context.adaptableApi.gridApi.getFirstRowNode();
const primaryKeyValue = firstNode!.id;
const open_pr_count = firstNode!.data['open_pr_count'];
const cellUpdateRequest: CellUpdateRequest = {
columnId: 'open_pr_count',
newValue: open_pr_count + 100,
primaryKeyValue: primaryKeyValue,
rowNode: firstNode,
};
context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
},
buttonStyle: {
tone: 'accent',
variant: 'raised',
},
},
],
},
],
},
chartingOptions: {
chartContainers: [
{
name: 'Above Grid',
element: '#demoOutputAbove',
},
],
},
initialState: {
Dashboard: {
Tabs: [
{Name: 'Charting', Toolbars: ['Charting', 'ButtonToolbar', 'Buttons']},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {CurrentTheme: 'dark'},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Total PRs',
ColumnId: 'total_pr_count',
Query: {
ScalarExpression: '[open_pr_count] + [closed_pr_count]',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
},
},
],
},
Charting: {
ChartDefinitions: [
{
Name: 'Top Frameworks',
Model: {
modelType: 'range',
chartId: 'frameworks-pie',
chartType: 'pie',
chartThemeName: 'ag-vivid-dark',
chartOptions: {
pie: {
background: {
visible: true,
},
padding: {
top: 20,
right: 20,
bottom: 20,
left: 20,
},
title: {
enabled: true,
text: 'Total PRs by Framework',
},
series: {
title: {
enabled: true,
text: '',
},
calloutLabel: {
enabled: true,
},
sectorLabel: {
enabled: true,
},
},
},
},
cellRange: {
rowStartIndex: 0,
rowEndIndex: 4,
columns: ['name', 'total_pr_count'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'total_pr_count',
'open_pr_count',
'closed_pr_count',
'github_stars',
'github_watchers',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'has_projects',
'has_pages',
'week_issue_change',
'open_issues_count',
'closed_issues_count',
],
ColumnSorts: [{ColumnId: 'github_stars', SortOrder: 'Desc'}],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {AdaptableReadyInfo, ChartDefinition} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
const topChartContainer = document.getElementById(
'demoOutputAbove'
) as HTMLDivElement;
const chartDefs: ChartDefinition[] =
adaptableApi.chartingApi.getChartDefinitions();
adaptableApi.chartingApi.showChartDefinition(chartDefs[0], topChartContainer);
};
```
```css
#demoOutputAbove {
display: flex;
}
```
---
# Standard Calculated Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-standard
- Standard Calculated Columns show a value that is derived using other cell values in the same row
- It can include as many Expression Functions and clauses as needed
The Expression provided by a Calculated Column is most commonly a [Standard Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md).
This evaluates **each row** in turn and returns a **single value** of any type.
The evaluation for a Standard Calculated Column value is typically derived dynamically, using the values in other cells of the same row.
- There is no limit in the number of [Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md) which can be included in a Calculated Column's Expression
- The Expression will update in real time as values in referenced columns change
- See [Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) to learn more about AdapTableQL, expression syntax, and the available functions
- Consult the [Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) topic for detailed information
### Defining a Standard Calculated Column
There are 5 properties that you need to provide when defining a Standard Calculated Column:
This `ColumnId` value is used to reference the Column in AdapTable State and in other objects (e.g. [Layouts](https://www.adaptabletools.com/docs/handbook-layouts/index.md)).
This value is used to refer to the Column in AdapTable UI.
It only needs to be provided if the `ColumnId` value is unsuitable.
This is the [Standard Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) for each row in the grid.
It is wrapped inside a `Query` property under the `ScalarExpression` key.
The Data Type of the Calculated Column should be provided in `CalculatedColumnSettings`.
It is a [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) value and the object's only mandatory property. Common values are `number`, `text` or `date`.
Additional Settings for the Calculated Column (other than mandatory `DataType`) can be provided, including:
- `Filterable`
- `Pivotable`
- `Sortable`
- `Groupable`
```tsx [[1,4, "ColumnId"],[1,16, "ColumnId"],[2,5, "FriendlyName"],[2,17, "FriendlyName"],[3,7, "ScalarExpression"],[3,19, "ScalarExpression"],[4,11, "DataType"],[4,23, "DataType"],[5,12, "Filterable"],[5,24, "Sortable"]]
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'total_pr_count',
FriendlyName: 'Total PRs',
Query: {
ScalarExpression:
'[open_pr_count] + [closed_pr_count]',
},
CalculatedColumnSettings: {
DataType: 'number',
Filterable: true,
},
},
{
ColumnId: 'popularity',
FriendlyName: 'Popularity',
Query: {
ScalarExpression:
'[github_stars] > 100000 ? "Very Popular" : [github_stars] > 30000 ? "Popular" : "Trending"',
},
CalculatedColumnSettings: {
DataType: 'text',
Sortable: true,
},
},
],
},
```
## Basic Expression
Most Calculated Column Expressions contain just one clause and uses the standard operators ('=', '>' etc.)
A very typical example is returning a mathematical evaluation on a few inputs.
**Example: Basic Calculated Columns**
Calculated Columns: Basic Standard
- This example has two Calculated Columns (using [Standard Expressions](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md)):
- `Subscribers Ratio` - divides Github Stars by Github Watchers
- `Total PRs` sums Open PRs and Closed PRs
### Expand to see the Calculated Column Definitions
The Calculated Columns are defined:
```ts
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Subscribers Ratio',
ColumnId: 'subscribersRatio',
Query: { ScalarExpression: '[github_stars] / [github_watchers]' },
CalculatedColumnSettings: {
ColumnTypes: ['first'],
Filterable: true,
Groupable: true,
DataType: 'number',
},
},
{
FriendlyName: 'Total PRs',
ColumnId: 'total_pr_count',
Query: { ScalarExpression: '[open_pr_count] + [closed_pr_count]' },
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
```
- Create a new Calculated Column that calculates how many days passed since a row was last updated
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Basic Calculated Columns',
columnOptions: {
columnTypes: ['first', 'second'],
},
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'subscribersRatio',
'github_stars',
'github_watchers',
'total_pr_count',
'open_pr_count',
'closed_pr_count',
],
Name: 'Standard Layout',
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Subscribers Ratio',
ColumnId: 'subscribersRatio',
Query: {
ScalarExpression: '[github_stars] / [github_watchers]',
},
CalculatedColumnSettings: {
ColumnTypes: ['first'],
Filterable: true,
Groupable: true,
DataType: 'number',
},
},
{
FriendlyName: 'Total PRs',
ColumnId: 'total_pr_count',
Query: {
ScalarExpression: '[open_pr_count] + [closed_pr_count]',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-subscribersRatio',
Scope: {
ColumnIds: ['subscribersRatio'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
],
},
},
};
```
## Complex Expression
However it is possible to create more complex Calculated Columns.
These can either include multiple clauses or it can leverage some of the more powerful Expression Functions.
It is also possible to reference [Custom Expression Functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions-custom/index.md) in a Calculated Column Expression.
Any value can be returned in a Calculated Column (i.e. date or string or boolean) and not solely a number
## Logic in Expressions
Calculated Column Expressions can also include [logic functions](https://www.adaptabletools.com/docs/adaptable-ql-expression-advanced-logic/index.md) if required.
These can take 2 forms:
- ternary logic, ie. if X, then Y, else Z
```ts
[Comments] > 100 ? 'Big' : [Comments] > 50 ? 'Medium' : 'Small'
```
- case statements, where different values are evaluated:
```ts
CASE WHEN [price] < 10 THEN 'low' WHEN [price] < 50 THEN 'medium' ELSE 'high' END
```
**Example: Calculated Columns: Complex Expressions**
Calculated Columns: Complex Expressions
- This demo contains 5 Calculated Columns which each contain a Standard Expression (of varying complexity and with varying Data types):
- `Years Old` - calculates how many years passed since each framework repo was created - returns a *Number*
- `Issues Open/Total Ratio` - shows ratio between open and total number of issues - returns a *Number*
- `PR Open/Total Ratio` - shows ratio between open and total number of pull-requests - returns a *Number*
- `Popularity` - specifies the popularity taking into account the number of stars using **ternary logic** - returns a *String*
- `Anniversary` - adds 1 year to the Created Date column - returns a *Date*
### Expand to see the Calculated Column Definitions and the AdapTableQL expressions used
```ts
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Years Old',
ColumnId: 'yearsOld',
Query: {
ScalarExpression: 'DIFF_YEARS(CURRENT_DAY(), [created_at])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Issues Open/Total Ratio',
ColumnId: 'open-total-issue-ratio',
Query: {
ScalarExpression:
'[open_issues_count] / ([open_issues_count] +[closed_issues_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'PR Open/Total Ratio',
ColumnId: 'open-total-pr-ratio',
Query: {
ScalarExpression:
'[open_pr_count] / ([open_pr_count] + [closed_pr_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Popularity',
ColumnId: 'popularity',
Query: {
ScalarExpression:
'[github_stars] > 100000 ? "Very Popular" : [github_stars] > 30000 ? "Popular" : "Trending"',
},
CalculatedColumnSettings: {
DataType: 'text',
},
},
{
FriendlyName: 'Anniversary',
ColumnId: 'anniversary',
Query: {
ScalarExpression: 'ADD_YEARS([created_at] , 1) ',
},
CalculatedColumnSettings: {
DataType: 'date',
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Complex Calculated Columns',
initialState: {
Dashboard: {
ModuleButtons: ['CalculatedColumn', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'CalculatedColumn'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'yearsOld',
'created_at',
'open-total-issue-ratio',
'open-total-pr-ratio',
'popularity',
'anniversary',
'github_stars',
],
Name: 'Standard Layout',
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
FriendlyName: 'Years Old',
ColumnId: 'yearsOld',
Query: {
ScalarExpression: 'DIFF_YEARS(CURRENT_DAY(), [created_at])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Issues Open/Total Ratio',
ColumnId: 'open-total-issue-ratio',
Query: {
ScalarExpression:
'[open_issues_count] / ([open_issues_count] +[closed_issues_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'PR Open/Total Ratio',
ColumnId: 'open-total-pr-ratio',
Query: {
ScalarExpression:
'[open_pr_count] / ([open_pr_count] + [closed_pr_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
},
{
FriendlyName: 'Popularity',
ColumnId: 'popularity',
Query: {
ScalarExpression:
'[github_stars] > 100000 ? "Very Popular" : [github_stars] > 30000 ? "Popular" : "Trending"',
},
CalculatedColumnSettings: {
DataType: 'text',
},
},
{
FriendlyName: 'Anniversary',
ColumnId: 'anniversary',
Query: {
ScalarExpression: 'ADD_YEARS([created_at] , 1) ',
},
CalculatedColumnSettings: {
DataType: 'date',
},
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-open-total-issue-ratio',
Scope: {
ColumnIds: ['open-total-issue-ratio', 'open-total-pr-ratio'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
},
},
},
{
Name: 'formatColumn-anniversary',
Scope: {
ColumnIds: ['anniversary'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'yyyy/MM/dd',
},
},
},
],
},
},
};
```
---
# Calculated Column Technical Reference
Canonical page: https://www.adaptabletools.com/docs/handbook-calculated-column-technical-reference
- Calculated Column Initial Adaptable State enables Calculated Columns to be defined at design time
- Calculated Column API Section of Adaptable API contains functions relating to [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md)
-------------
## Calculated Column State
The Calculated Column section of Adaptable State contains an array of `CalculatedColumn` objects:
| Property | Type | Description |
| --- | --- | --- |
| [CalculatedColumns](https://www.adaptabletools.com/docs/reference/calculatedcolumnstate.md#calculatedcolumns) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md)`[]` | Collection of Calculated Columns |
### Calculated Column
The Calculated Column is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [CalculatedColumnSettings](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#calculatedcolumnsettings) | [`CalculatedColumnSettings`](https://www.adaptabletools.com/docs/reference/calculatedcolumnsettings.md) | Additional optional properties for Column (e.g. filterable, resizable) |
| [ColumnId](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#columnid) | `string` | Name of Calculated Column |
| [FriendlyName](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#friendlyname) | `string` | Name to be used in Column Header; if blank `ColumnId` is used |
| [Query](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#query) | [`AdaptableCalculatedColumnQuery`](https://www.adaptabletools.com/docs/reference/adaptablecalculatedcolumnquery.md) | Scalar/AggregatedScalar Query used by AdapTableQL to evaluate Column's value |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
### Calculated Column Settings
The Calculated Column Settings property contains additional options for the Calculated Column:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [ShowToolTip](https://www.adaptabletools.com/docs/reference/calculatedcolumnsettings.md#showtooltip) | `boolean` | Show underlying Expression as Tooltip when hovering over a cell | false |
But it also inherits from [`SpecialColumnSettings`](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md) which is defined as follows:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [Aggregatable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#aggregatable) | `boolean` | Whether Column can be used in an aggregation when grouping | false |
| [ColumnTypes](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#columntypes) | `string[]` | Custom column types added to AG Grid Column Types when object is created | |
| [DataType](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#datatype) | [`AdaptableColumnDataType`](https://www.adaptabletools.com/docs/reference/adaptablecolumndatatype.md) | Expression's return value DataType, only mandatory property | |
| [Filterable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#filterable) | `boolean` | Whether Column is filterable | false |
| [Groupable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#groupable) | `boolean` | Whether Column can be grouped | false |
| [HeaderToolTip](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#headertooltip) | `string` | Tooltip to show in the Column Header (not cells) | |
| [Pivotable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#pivotable) | `boolean` | Whether Column can be used when grid is in pivot mode | false |
| [Resizable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#resizable) | `boolean` | Whether Column can be resized (by dragging column header edges) | false |
| [Sortable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#sortable) | `boolean` | Whether Column is sortable | false |
| [SuppressMenu](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#suppressmenu) | `boolean` | Whether if no menu should be shown for this Column header. | false |
| [SuppressMovable](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#suppressmovable) | `boolean` | Whether if this Column should be movable via dragging | false |
| [Width](https://www.adaptabletools.com/docs/reference/specialcolumnsettings.md#width) | `number` | Preferred (pixel) Column Width; if unset, calculated dynamically by AG Grid | |
-------------
## Calculated Column Changed Event
The Calculated Column Changed Event fires whenever the Calculated Column State changes.
It provides full information about the new Calculated Column and what triggered the change.
### Calculated ColumnChangedInfo
The event comprises a single [`CalculatedColumnChangeInfo`](https://www.adaptabletools.com/docs/reference/calculatedcolumnchangedinfo.md) object which contains details about what action triggered the change and the associated Caluculated Column.
| Property | Type | Description |
| --- | --- | --- |
| [actionName](https://www.adaptabletools.com/docs/reference/calculatedcolumnchangedinfo.md#actionname) | `string` | What caused CalculatedColumn State to change (i.e. Add, Edit, Delete) |
| [calculatedColumn](https://www.adaptabletools.com/docs/reference/calculatedcolumnchangedinfo.md#calculatedcolumn) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md) | Calculated Column that has been added, edited or deleted |
| [calculatedColumnExpressionAST](https://www.adaptabletools.com/docs/reference/calculatedcolumnchangedinfo.md#calculatedcolumnexpressionast) | `any` | AST for Current Calculated Column Expression |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/calculatedcolumnchangedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
### Action Names
The value for the `actionName` property can be one of:
- `CALCULATED_COLUMN_ADD`
- `CALCULATED_COLUMN_EDIT`
- `CALCULATED_COLUMN_DELETE`
### Event Subscription
Subscribing to the Event is done the same way as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md):
```ts
api.eventApi.on('CalculatedColumnChanged', (eventInfo: CalculatedColumnChangedInfo) => {
// do something with the info
});
```
-------------
## Calculated Column API
| Method | Returns | Description |
| --- | --- | --- |
| [addCalculatedColumn(calcColumn)](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#addcalculatedcolumn) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md) | Adds new Calculated Column |
| [deleteCalculatedColumn(columnId)](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#deletecalculatedcolumn) | `void` | Deletes Calculated Column with given ColumnId from Adaptable State |
| [editCalculatedColumn(calcColumn)](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#editcalculatedcolumn) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md) | Updates given Calculated Column in Adaptable State |
| [getAggregatedCalculatedColumns()](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#getaggregatedcalculatedcolumns) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md)`[]` | Retrieves all Aggregated Calculated Columns in Adaptable State |
| [getCalculatedColumnById(id)](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#getcalculatedcolumnbyid) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md) | Retrieves Calculated Column by the technical ID (from `CalculatedColumnState`) |
| [getCalculatedColumnForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#getcalculatedcolumnforcolumnid) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md)` \| undefined` | Gets Calculated Column, if any, for given ColumnId |
| [getCalculatedColumns()](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#getcalculatedcolumns) | [`CalculatedColumn`](https://www.adaptabletools.com/docs/reference/calculatedcolumn.md)`[]` | Retrieves all Calculated Columns in Adaptable State |
| [getCalculatedColumnState()](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#getcalculatedcolumnstate) | [`CalculatedColumnState`](https://www.adaptabletools.com/docs/reference/calculatedcolumnstate.md) | Retrieves Calculated Column section from Adaptable State |
| [openCalculatedColumnSettingsPanel()](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#opencalculatedcolumnsettingspanel) | `void` | Opens Settings Panel with Calculated Column section selected and visible |
| [refreshAggregatedCalculatedColumn(columnId)](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#refreshaggregatedcalculatedcolumn) | `void` | Re-calculates the aggregated CalculatedColumn (defined with a `AggregatedScalarExpression`) with the given `columnId` |
| [refreshAggregatedCalculatedColumns()](https://www.adaptabletools.com/docs/reference/calculatedcolumnapi.md#refreshaggregatedcalculatedcolumns) | `void` | Re-calculates all aggregated CalculatedColumns (defined with a `AggregatedScalarExpression`) |
---
# Cell Editors
Canonical page: https://www.adaptabletools.com/docs/handbook-cell-editors
- AdapTable provides 4 Cell Editors to enable quick data entry and edits:
- Select editor: used for choosing from list of values
- Numeric cell editor: used for editing numeric columns
- Date Picker: used for editing date columns
- Percentage cell editor: used for when editing values as percentages
AdapTable provides 4 Cell Editors so that data can can be quickly and safely entered into AG Grid:
| Editor | Columns Used | Always Used | Used in Filters |
| ------------------------------------------------------------------------------------- | -------------------------------- | :-----------: | :-------------: |
| [Select (Dropdown) Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-select/index.md) | All Columns | If configured | ❌ |
| [Numeric Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-numeric/index.md) | Numeric Columns | ✅ | ✅ |
| [Date Picker](https://www.adaptabletools.com/docs/handbook-cell-editors-date-picker/index.md) | Date Columns | ✅ | ✅ |
| [Percentage Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-percentage/index.md) | Numeric Columns with % Rendering | ❌ | ❌ |
- Numeric Cell Editor and Date Picker will be used by default by AdapTable for numeric and date columns
- However if a bespoke Cell Editor is provided in GridOptions, that **will take precedence**
---
# Date Picker
Canonical page: https://www.adaptabletools.com/docs/handbook-cell-editors-date-picker
- A Date Picker is provided by AdapTable whenever a date cell is edited
- It is also used when filtering a date column
- The Date Picker is highly configurable and themable
The Date Picker is automatically used by default in AdapTable when **editing** all Date cells.
A Date cell is one where the [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) property for the column is `date`
It is also used when **filtering** any Date Column.
This can be changed by setting `showDatePicker` to _false_ in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
The Date Picker is designed to be easily themable and can be heavily customised with CSS Variables.
## Value Parser
If the Column Definition in AG Grid has a `valueParser` (provided as a function), that will be invoked **before** setting the value for the cell.
This is useful because dates can be stored as strings, numbers or Date instances, but the value parser will be called with a `Date` instance.
- It's your responsibility to transform that value to the format required for persisting it to the grid
- We strongly recommend you specify a `colDef.valueParser` function
## Customising
Buttons
Date Format
**Example: Date Picker Customising**
Customise the AdapTable Date Picker
- This demo shows some ways to customize the AdapTable Date Picker component
- The default Buttons have been set to `Today`, `Yesterday` and `Next Workday`
- Show Week Numbering is on
- Days not in the current month are hidden
### Open to see the Date Picker Configuration
This is the code used to configure the Date Picker in this demo:
```ts
userInterfaceOptions: {
dateInputOptions: {
datepickerButtons: ['today', '-', 'yesterday', 'nextWorkday'],
showWeekNumber: true,
showOutsideDays: false,
},
},
```
- Open the Date Picker in the Filter Bar for one of the Date columns and see how it looks
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Date Picker Variables',
userInterfaceOptions: {
dateInputOptions: {
datepickerButtons: ['today', '-', 'yesterday', 'nextWorkday'],
showWeekNumber: true,
showOutsideDays: false,
},
},
initialState: {
Dashboard: {
ModuleButtons: ['SettingsPanel', 'Theme'],
Tabs: [
{
Name: 'Default',
Toolbars: ['Theme'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'created_at',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Theming
The Date Picker can be fully styled - colours, look and feel, borders etc.
**Example: Date Picker Theming**
Theming the AdapTable Date Picker
- This demo shows how to theme the AdapTable Date Picker component.
### Open to see the Date Picker Configuration
This is the code used to theme the Date Picker in this demo:
```css
/* Date picker */
--ab-cmp-datepicker__background: rgb(238, 238, 238);
--ab-cmp-datepicker__selected-color: rgb(98, 0, 255);
--ab-cmp-datepicker__selected-text-color: rgb(255, 255, 255);
--ab-cmp-datepicker__selected-border-radius: 30%;
--ab-cmp-datepicker__day-border-radius: 30%;
--ab-cmp-datepicker__border: 1px solid rgb(0, 4, 250);
--ab-cmp-datepicker__cell-size: 40px;
```
- Open the Date Picker in the Filter Bar for one of the Date columns and see how it looks
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Date Picker Theming',
initialState: {
Dashboard: {
ModuleButtons: ['SettingsPanel', 'Theme'],
Tabs: [
{
Name: 'Default',
Toolbars: ['Theme'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'created_at',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```css
/* Date Picker Colors */
:root.ab--theme-light {
--ab-cmp-datepicker__background: rgb(238, 238, 238);
--ab-cmp-datepicker__selected-color: rgb(98, 0, 255);
--ab-cmp-datepicker__selected-text-color: rgb(255, 255, 255);
--ab-cmp-datepicker__selected-border-radius: 30%;
--ab-cmp-datepicker__day-border-radius: 30%;
--ab-cmp-datepicker__border: 1px solid rgb(0, 4, 250);
--ab-cmp-datepicker__cell-size: 40px;
}
:root.ab--theme-dark {
--ab-cmp-datepicker__background: rgb(41, 0, 88);
--ab-cmp-datepicker__selected-color: rgb(213, 187, 255);
--ab-cmp-datepicker__selected-text-color: rgb(255, 255, 255);
--ab-cmp-datepicker__selected-border-radius: 30%;
--ab-cmp-datepicker__day-border-radius: 30%;
--ab-cmp-datepicker__border: 1px solid rgb(0, 4, 250);
--ab-cmp-datepicker__cell-size: 40px;
}
```
## Date Input Options
The `dateInputOptions` property in [`UserInterfaceOptions`](https://www.adaptabletools.com/docs/reference/userinterfaceoptions.md) contains a number of properties for managing the Date Picker:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [dateFormat](https://www.adaptabletools.com/docs/reference/dateinputoptions.md#dateformat) | `string` | Format string for formatting date input field | 'yyyy-MM-dd' (ISO 8601 format) |
| [datepickerButtons](https://www.adaptabletools.com/docs/reference/dateinputoptions.md#datepickerbuttons) | `DatepickerButton[]` | List of buttons which are displayed in the datepicker overlay in the given order (provide empty array to display no buttons); custom button layout and positioning is achievable with the special elements `-` and `\|` | ['close','today'] |
| [locale](https://www.adaptabletools.com/docs/reference/dateinputoptions.md#locale) | `any` | Locale object (to localize Date Picker) | `en-US` |
| [showOutsideDays](https://www.adaptabletools.com/docs/reference/dateinputoptions.md#showoutsidedays) | `boolean` | Display outside days (i.e. those falling in next or previous month) | true |
| [showWeekNumber](https://www.adaptabletools.com/docs/reference/dateinputoptions.md#showweeknumber) | `boolean` | Display the week numbers column | false |
| [useNativeInput](https://www.adaptabletools.com/docs/reference/dateinputoptions.md#usenativeinput) | `boolean` | Use browser specific date input instead of AdapTable's Date Picker | false |
---
# Numeric Cell Editor
Canonical page: https://www.adaptabletools.com/docs/handbook-cell-editors-numeric
- Numeric Cell Editor is provided by AdapTable whenever a numeric cell is edited
- It is also used when filtering a numeric column
The Numeric Cell Editor is used, by default in AdapTable, when editing all numeric Columns.
A numeric column is one where the [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) is set to `number`.
It is also used when a [FreeText Column](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) is defined as numeric
It displays an editor with arrows at the end to move up and down and only accepts numbers (with fractions).
The Numeric Cell Editor will take into account any [Shortcuts](https://www.adaptabletools.com/docs/handbook-editing-shortcut/index.md) that have been created
## Cell Editor Params
The Numeric Cell Editor can be configured by specifying `cellEditorParams` in the AG Grid Column Definition.
This maps to the [`AdaptableNumberCellEditorParams`](https://www.adaptabletools.com/docs/reference/adaptablenumbercelleditorparams.md) object and contains 2 main properties:
- `showClearButton` - specifies whether to show the *Clear* button in the Editor
If set to `true` (the default value), it works together with `emptyValue`
- `emptyValue` - value to set in a cell when the Clear button is pressed (defaults to an empty string)
- Some AG Grid Column Definitions have a `valueParser` which is provided as a function
- In that use case, the function will be invoked **before** setting the value for the cell
**Example: Numeric Cell Editor Params**
Numeric Editor with Cell Editor Params
- This demo illustrates how to use the Numeric Cell Editor. For the `GitHub Stars` column, we provide 2 Cell Editor Params:
- `showClearButton` is set to *true* so we see a Clear Button (that is the default behaviour anyway)
- `emptyValue` has been set to 1000 (instead of default of 0)
- Clear a cell in the Numeric Editor in the `Github Stars` Column and note how the edit value changes to 1000
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Numeric Editor Params',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'license',
'created_at',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'name',
cellDataType: 'text',
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
cellEditorParams: {
emptyValue: 1000,
showClearButton: true,
},
},
{
field: 'license',
cellDataType: 'text',
editable: true,
enablePivot: true,
enableRowGroup: true,
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{field: 'has_wiki', headerName: 'Has Wiki', cellDataType: 'boolean'},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
];
```
---
# Percentage Cell Editor
Canonical page: https://www.adaptabletools.com/docs/handbook-cell-editors-percentage
- The Percentage Cell Editor allows cells where the value is a percentage to be edited as such
- This works in the same fashion as when editing percentages in Excel
The Percentage Cell Editor allows cells, where the value is a percentage, to also be edited as percentages.
The Editor is designed to work in exactly the same way as percentage editors in Excel.
There is a parallel `AdaptableReactPercentageEditor` available for us in [AdapTable React](https://www.adaptabletools.com/docs/index.md)
For example a value of **0.123456** will be displayed in the Percentage Cell Editor as **12.3456%**.
- Columns that use the Percentage Cell Editor are typically also given a [Number Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md) of *Percentage*
- This ensures that the Display Value and the Cell Editor Value remain consistent
**Example: Percentage Editor**
AdapTable Percentage Editor
- This demo shows how to use the Percentage Cell Editor
- We have added a new column called `Usage` which has values like 0.12345, 0.13579 etc.
- In *ColumnDefs* we set the `CellEditor` for the column to be the `AdaptablePercentageEditor`
- We also created a [Number Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md) for the `Usage` Column of Percentage
### Open to see how the Percentage Cell Editor is set up
In ColumnDefs we define the Column and add the Cell Editor:
```ts
{
field: 'usage',
headerName: 'Usage',
cellDataType: 'number',
editable: true,
cellEditor: AdaptablePercentageEditor,
},
```
We create a [Number Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md) for the `Usage` Column of Percentage:
```ts
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-usage-213',
Scope: {
ColumnIds: ['usage'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
Suffix: '%',
Multiplier: 100,
},
},
},
],
},
```
- Try to edit a cell in the `Usage` Column and see that the Percentage Editor is used
- Suspend the Format Column to see the real underlying value for the `Usage` column
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Percentage Editor',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-usage',
Scope: {
ColumnIds: ['usage'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
Suffix: '%',
Multiplier: 100,
},
},
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'usage',
'language',
'license',
'created_at',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
export interface WebFramework {
id: number;
name: string;
usage?: number;
full_name?: string;
html_url?: string;
description: string;
created_at: string;
updated_at: string;
pushed_at: string;
homepage?: string;
github_stars: number;
language: string;
forks_count?: number;
open_issues_count: number;
license: string;
topics?: string[];
github_watchers: number;
has_projects: boolean;
has_wiki: boolean;
has_pages: boolean;
closed_issues_count: number;
open_pr_count: number;
closed_pr_count: number;
week_issue_change: number;
}
export const rowData: WebFramework[] = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 179429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
usage: 0.123456,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'Very Good',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78348,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
usage: 0.13579,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description: 'Good',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 191435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
usage: 0.2468,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Very Good Also',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 53935,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
usage: 1.234567,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description: 'Very New But Good',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 19338,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description: 'Very Well Liked with Good Reviews',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 9752,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
usage: 0.222222,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 11049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
usage: 0.3333333,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
usage: 0.654321,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
usage: 0.97531,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date('2021-12-19T21:06:01').toDateString(),
homepage: 'https://solidjs.com',
github_stars: 13119,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 23,
usage: 0.8642,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 13064,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
usage: 0.125456,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
usage: 0.7878545,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
usage: 0.54564525,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 27840,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
usage: 0.8964,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 10122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
usage: 0.786528,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date('2021-12-20T00:37:09').toDateString(),
homepage: 'https://redwoodjs.com',
github_stars: 10334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
usage: 0.123456,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 20095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
```ts
import {ColDef} from 'ag-grid-enterprise';
import {AdaptablePercentageEditor} from '@adaptabletools/adaptable';
export const columnDefs: ColDef[] = [
{
field: 'name',
cellDataType: 'text',
},
{
field: 'usage',
headerName: 'Usage',
cellDataType: 'number',
editable: true,
cellEditor: AdaptablePercentageEditor,
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
field: 'license',
cellDataType: 'text',
editable: true,
enablePivot: true,
enableRowGroup: true,
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{field: 'has_wiki', headerName: 'Has Wiki', cellDataType: 'boolean'},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
];
```
## Cell Editor Params
Similar to the [Numeric Cell Editor](https://www.adaptabletools.com/docs/handbook-cell-editors-numeric/index.md), the Percentage Editor is configurable.
This is done using the `cellEditorParams` property in the AG Grid Column Definition.
This maps to the [`AdaptablePercentageCellEditorParams`](https://www.adaptabletools.com/docs/reference/adaptablepercentagecelleditorparams.md) object, which contains 2 properties:
- `showClearButton` - whether to show the *Clear* button (defaults to *true*)
When set to `true`, this property works together with `emptyValue`
- `emptyValue` - value to set for the cell when the *Clear* button is clicked (defaults to an empty string)
If the colDef has a `valueParser` provided as a function, that will be used **before** setting the value for the cell
**Example: Percentage Editor Params**
Percentage Editor with Cell Editor Params
- This demo contains the same Percentage Cell Editor (and Display Format) as the demo above but with 2 Cell Editor Params set:
- `showClearButton` is set to *true* so we see a Clear Button
- `emptyValue` has been set to 1 (instead of default of 0)
### Open to see how the Percentage Cell Editor is set up
In ColumnDefs we define the Column and add the Cell Editor and add 2 Cell Editor Params:
```ts
{
field: 'usage',
headerName: 'Usage',
cellDataType: 'number'
editable: true,
cellEditor: AdaptablePercentageEditor,
cellEditorParams: {
emptyValue: 1,
showClearButton: true,
},
},
```
- Try to edit a cell in the `Usage` Column and see that the Percentage Editor is used
- Note that there is now a `Clear` button, and when it is clicked the value changes to 1%
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Percentage Editor Params',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-usage',
Scope: {
ColumnIds: ['usage'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 2,
Suffix: '%',
Multiplier: 100,
},
},
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'usage',
'language',
'license',
'created_at',
'updated_at',
'pushed_at',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
export interface WebFramework {
id: number;
name: string;
usage?: number;
full_name?: string;
html_url?: string;
description: string;
created_at: string;
updated_at: string;
pushed_at: string;
homepage?: string;
github_stars: number;
language: string;
forks_count?: number;
open_issues_count: number;
license: string;
topics?: string[];
github_watchers: number;
has_projects: boolean;
has_wiki: boolean;
has_pages: boolean;
closed_issues_count: number;
open_pr_count: number;
closed_pr_count: number;
week_issue_change: number;
}
export const rowData: WebFramework[] = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 179429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
usage: 0.123456,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'Very Good',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78348,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
usage: 0.13579,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description: 'Good',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 191435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
usage: 0.2468,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Very Good Also',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 53935,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
usage: 1.234567,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description: 'Very New But Good',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 19338,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description: 'Very Well Liked with Good Reviews',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 9752,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
usage: 0.222222,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 11049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
usage: 0.3333333,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
usage: 0.654321,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
usage: 0.97531,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date('2021-12-19T21:06:01').toDateString(),
homepage: 'https://solidjs.com',
github_stars: 13119,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 23,
usage: 0.8642,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 13064,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
usage: 0.125456,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
usage: 0.7878545,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
usage: 0.54564525,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 27840,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
usage: 0.8964,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 10122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
usage: 0.786528,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date('2021-12-20T00:37:09').toDateString(),
homepage: 'https://redwoodjs.com',
github_stars: 10334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
usage: 0.123456,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 20095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
```ts
import {ColDef} from 'ag-grid-enterprise';
import {AdaptablePercentageEditor} from '@adaptabletools/adaptable';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
{
field: 'name',
cellDataType: 'text',
},
{
field: 'usage',
headerName: 'Usage',
cellDataType: 'number',
editable: true,
cellEditor: AdaptablePercentageEditor,
cellEditorParams: {
emptyValue: 1,
showClearButton: true,
},
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
field: 'license',
cellDataType: 'text',
editable: true,
enablePivot: true,
enableRowGroup: true,
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{field: 'has_wiki', headerName: 'Has Wiki', cellDataType: 'boolean'},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
];
```
---
# Select Editor
Canonical page: https://www.adaptabletools.com/docs/handbook-cell-editors-select
- The Select Editor wraps the AG Grid Rich Select Editor, and displays automatically when a cell is being edited
- By default the Select Editor will contain the current distinct values in the column
- However, if required, a different set of values can be provided by developers for the user to see
AdapTable can be configured to display the the [AG Grid Rich Select Editor](https://www.ag-grid.com/javascript-data-grid/provided-cell-editors-rich-select/) dynamically during a cell edit.
The Column must be configured as **editable** in the AG Grid column schema for the Select Editor to appear
The `showSelectCellEditor` property in [Edit Options](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md) defines which Columns will display a Select Editor.
### `showSelectCellEditor`
Which Columns use a Select Editor
Option used to configure which Columns use AG Grid's Rich Select Editor when being edited.
The property is a function that receives [`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md) and returns a boolean.
The `AdaptableColumnContext` simply provides the current Column:
| Property | Type | Description |
| --- | --- | --- |
| [column](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md#column) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`` | The current Column |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
```ts {3}
editOptions: {
// Display Select Editors for the Country and Currency columns
showSelectCellEditor: context => {
return context.column.columnId === 'currency' || context.column.columnId === 'country';
}
},
```
**Example: Select Editors**
Providing Select Editors to speed up data entry
- In this example Select Editors are configured for 2 Columns - `License` and `Language`
- Both Columns display a dropdown when a cell is clicked
- Click on a cell in the `Licence` or `Language` columns and see how a dropdown appears showing the distinct values in the column
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Select Editors',
editOptions: {
showSelectCellEditor: context => {
return (
context.column.columnId === 'language' ||
context.column.columnId === 'license'
);
},
},
initialState: {
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
{
field: 'name',
cellDataType: 'text',
},
{
field: 'language',
cellDataType: 'text',
enablePivot: true,
enableRowGroup: true,
},
{
field: 'github_stars',
headerName: 'GitHub Stars',
cellDataType: 'number',
enableValue: true,
},
{
field: 'license',
cellDataType: 'text',
editable: true,
enablePivot: true,
enableRowGroup: true,
},
{
field: 'week_issue_change',
headerName: 'Issue Change',
cellDataType: 'number',
enableValue: true,
},
{
field: 'created_at',
headerName: 'Created',
cellDataType: 'date',
},
{field: 'has_wiki', headerName: 'Has Wiki', cellDataType: 'boolean'},
{
field: 'updated_at',
headerName: 'Updated',
cellDataType: 'date',
},
{
field: 'pushed_at',
headerName: 'Pushed',
cellDataType: 'date',
},
{
field: 'github_watchers',
headerName: 'GitHub Watchers',
cellDataType: 'number',
enableValue: true,
},
{
field: 'topics',
cellDataType: 'textArray',
editable: false,
sortable: false,
},
{
field: 'open_issues_count',
headerName: 'Open Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_issues_count',
headerName: 'Closed Issues',
cellDataType: 'number',
enableValue: true,
},
{
field: 'description',
cellDataType: 'text',
sortable: false,
},
{
field: 'open_pr_count',
headerName: 'Open PRs',
cellDataType: 'number',
enableValue: true,
},
{
field: 'closed_pr_count',
headerName: 'Closed PRs',
cellDataType: 'number',
enableValue: true,
},
{field: 'has_projects', headerName: 'Has Projects', cellDataType: 'boolean'},
{field: 'has_pages', headerName: 'Has Pages', cellDataType: 'boolean'},
];
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
singleClickEdit: true,
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
## Custom Editor Values
By default the Select Editor will automatically display a list of the **distinct** values in that column.
However it is possible to provide a bespoke list of items to display in the Select Editor.
This is done via the by using the `customEditColumnValues` property (also in [Edit Options](https://www.adaptabletools.com/docs/handbook-editing-technical-reference/index.md)).
See [Providing Custom Column Values when Editing](https://www.adaptabletools.com/docs/handbook-editing-custom-column-values/index.md) for more information and a demo
## Row Forms
AdapTable provides [Row Forms](https://www.adaptabletools.com/docs/handbook-row-form/index.md) to enable safe and easy editing via a dynamic Form.
Any Select Editors which have been provided are also available when editing the cell using Row Forms.
The Select Editor is also displayed when using `Create` or `Clone` in a Row Form
---
# Using AG Grid Charts
Canonical page: https://www.adaptabletools.com/docs/handbook-charts
- AG Grid charts are feature-rich work seamlessly in AdapTable
- The additional charting-related features that AdapTable currently provides are:
- persistence of charts in Adaptable State
- ability to host multiple chart windows
- Future releases of AdapTable will add extended support for AG Grid Charts including:
- improved chart definitions
- support for non-contiguous chart ranges
AdapTable fully supports AG Grid Charting and adds a few features around chart accessability.
## Saving Charts
Charts created in AG Grid can be saved into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
The `saveChartBehaviour` property in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) has 3 potential values:
- `auto`: all created charts are saved automatically in Adaptable State
- `manual`: a popup is shown prompting the user to save the chart and provide a name
- `none`: charts are not saved into AdapTable State (the default value)
**Example: Saving AG Grid Charts**
How to leverage AG Grid's Charts in AdapTable
- This demo shows how straightforward it is save AG Grid Charts in AdapTable
- Because `saveChartBehaviour` in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) is set to `manual` a Notification appears when creating a Chart
- Any charts which are created will then appear display in the Charts Toolbar, Tool Panel and Status Panel where they can be re-opened if required
### Expand to see Charting Options
```ts
chartingOptions: {
saveChartBehaviour: 'manual',
},
```
- Create a chart using the currently selected cells and give it a name in the popup provided
- Close the chart and see that you can open it again at any time using the Charts Toolbar
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Saving Charts',
chartingOptions: {
saveChartBehaviour: 'manual',
chartContainers: [],
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Charting',
Toolbars: ['Charting'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'github_stars',
'github_watchers',
'name',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
// enable charts and set a theme
enableCharts: true,
chartThemes: ['ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
setTimeout(() => {
// Pick 5 cells in 2 columns
const colsToSelect: string[] = ['github_stars', 'github_watchers'];
const startIndex: number = 1;
const endIndex: number = 5;
// Select them in AdapTable using AdapTable's GridAPI
adaptableApi.gridApi.selectCellRange({
columnIds: colsToSelect,
rowIndexStart: startIndex,
rowIndexEnd: endIndex,
});
}, 10);
};
```
## Displaying Charts
AdapTable can be configured to display charts in various locations provided by users.
There is no restriction on the number of Charts which can be displayed in each location.
See [Configuring Charts](https://www.adaptabletools.com/docs/handbook-charts-configuring/index.md) for more information and accompanying demos
## External Charts
AdapTable supports both AG Grid Charts (the most common use case) and External Charts.
Developers are able to provide their own charts, and use AdapTable to save and re-render them as required.
See [External Chart Libraries](https://www.adaptabletools.com/docs/handbook-charts-external/index.md) for full details
## Cross Filter Charts
Cross Filtering Charts is semi-supported in AdapTable.
Changing a Filter in AdapTable will update the Chart; however changing the chart will not update the Filter.
This is a known issue and will be addressed in a future release
**Example: Cross Filter Charts**
Supporting AG Grid's Cross Filter Charts
- Filter the Language and License columns and see the Charts update
- Note: Changing the Chart will not filter the Grid (at present)
```ts
import {
AdaptableColumn,
AdaptableColumnContext,
AdaptableOptions,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Displaying Charts',
filterOptions: {
columnFilterOptions: {
defaultTextColumnFilter: 'In',
},
},
chartingOptions: {
saveChartBehaviour: 'none',
chartContainers: [
{
name: 'Above Grid',
element: '#demoOutputAbove',
chartsDisplay: 'multiple',
},
],
},
initialState: {
Dashboard: {
Tabs: [{Name: 'Charting', Toolbars: ['Charting']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {
CurrentTheme: 'dark',
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'language',
'github_stars',
'license',
'github_watchers',
'name',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'has_projects',
'has_pages',
'week_issue_change',
],
ColumnSorts: [{ColumnId: 'github_stars', SortOrder: 'Desc'}],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
enableCharts: true,
chartThemes: ['ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {AdaptableReadyInfo, ChartDefinition} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({agGridApi}: AdaptableReadyInfo) => {
agGridApi.createCrossFilterChart({
chartType: 'pie',
cellRange: {
columns: ['language', 'github_stars'],
rowStartIndex: 0,
rowEndIndex: 24,
},
aggFunc: 'sum',
chartThemeOverrides: {
common: {
title: {
enabled: true,
text: 'Github Stars by Language',
},
},
pie: {
series: {
title: {
enabled: false,
},
},
},
},
chartContainer: document.querySelector('#demoOutputAbove') as HTMLElement,
});
agGridApi.createCrossFilterChart({
chartType: 'bar',
cellRange: {
columns: ['license', 'github_watchers'],
rowStartIndex: 0,
rowEndIndex: 24,
},
aggFunc: 'count',
chartThemeOverrides: {
common: {
title: {
enabled: true,
text: 'Watchers by License',
},
legend: {
enabled: false,
},
},
},
chartContainer: document.querySelector('#demoOutputAbove') as HTMLElement,
});
//adaptableApi.chartingApi.showChartDefinition(chartDefs[1], topChartContainer);
};
```
```css
#demoOutputAbove {
display: flex;
}
```
## UI Entitlements
The UI Entitlements behaviour for Charts is as expected for `Full` and `Hidden` [`Access Levels`](https://www.adaptabletools.com/docs/reference/accesslevel.md).
The `ReadOnly` Entitlement behaviour is that Charts will display, and users can create AG Grid charts, but will not be permitted to save them.
---
# Configuring Charts
Canonical page: https://www.adaptabletools.com/docs/handbook-charts-configuring
- AG Grid Charts can be defined and saved with AdapTable State
- Locations can be provided where AG Grid Charts can be displayed
## Defining Charts
AdapTable allows developers to [define](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) Charts and save them in [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
- This can be done at design-time and the AG Grid Charting Model can be part of the definition
- But more typically it will be done via the methods in [Charting API](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md)
Each Chart Definition contains just 2 properties:
- Name of the Chart - how it appears in the AdapTable UI
- Chart Model - the underlying AG Grid Chart definition
## Providing Chart Locations
AdapTable also allows developers to provide details Chart Locations.
This is done through the `chartContainers` property of [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md).
Each location contains a Name and a reference to the `Div` element where Charts can be displayed.
### Understanding Chart Containers
The [`ChartContainer`](https://www.adaptabletools.com/docs/reference/chartcontainer.md) object is defined as follows:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [chartsDisplay](https://www.adaptabletools.com/docs/reference/chartcontainer.md#chartsdisplay) | `'single' \| 'multiple'` | Whether 1 or more Charts can be displayed in same location | 'single' |
| [element](https://www.adaptabletools.com/docs/reference/chartcontainer.md#element) | `HTMLElement \| string` | Location - can be HTMLElement or CSS Selector | |
| [name](https://www.adaptabletools.com/docs/reference/chartcontainer.md#name) | `string` | Name of Container's Location - used in Dropdowns | |
As can be seen it allows for 2 things to be configured:
- the Div where the Chart is displayed - provided either by `name` or as an `element`
- whether more than one Chart can be displayed in the Container - by setting the `chartsDisplay` property
The default Chart Container is the one provided by AG Grid and named 'AG Grid Window' by AdapTable
Use the `agGridContainerName` property in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) to provide a different name for this container
## Opening Charts Automatically
### On startup
Set `restoreChartsOnReady` in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) to open persisted charts when AdapTable loads:
- `true` or `'all'` — every chart in `Charting.ChartDefinitions`
- `string[]` — chart **names** to open (each definition's `Name` property)
### Per layout
Add `OpenCharts` to a [Table Layout](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md) or [Pivot Layout](https://www.adaptabletools.com/docs/handbook-layouts-pivot/index.md):
```ts
OpenCharts: [
{ ChartName: 'Top Frameworks', ContainerName: 'Top Window' },
{ ChartName: 'Summary Chart' }, // optional — uses the AG Grid chart window
],
```
Chart names must be unique across all AG Grid and external chart definitions. The chart wizard enforces this when saving or editing.
When the layout is selected, AdapTable closes other open AG Grid charts and opens the listed charts in the given containers. Use an empty array (`OpenCharts: []`) to close all charts for that layout.
See [Charts in Layout State](https://www.adaptabletools.com/docs/handbook-charts-using/index.md) for a full demo
**Example: Chart Locations**
Showing AG Grid Charts in different locations
- This example demonstrates how to define Charts and Chart Locations
- 2 Charts are provided in [Charts Initial Adaptable State](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md):
- `Top Frameworks` - a Pie Chart
- `Issues and PRs` - a 100% stacked Bar Chart
- 2 Chart locations are provided in the `chartContainers` property of [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md):
- `Top Window` - appears above the Grid
- `Bottom Window` - appears below the Grid
- Additionally the `agGridContainerName` property has been set to 'Over Grid' - which overrides default property of 'AG Grid Window'
### Expand to see the 2 Chart Locations provided
```ts
chartingOptions: {
saveChartBehaviour: 'manual',
chartContainers: [
{
name: 'Top Window',
element: topChartContainer,
},
{
name: 'Bottom Window',
element: '#demoOutputBelow',
},
],
},
```
- Open _Top Frameworks_ in the `Top Window` chart location
- Open _Issues and PR's_ in the `Bottom Window` chart location
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Chart Locations',
chartingOptions: {
chartContainers: [
{
name: 'Above Grid',
element: '#demoOutputAbove',
},
{
name: 'Below Grid',
element: '#demoOutputBelow',
},
],
agGridContainerName: 'Over Grid',
},
initialState: {
Dashboard: {
Tabs: [{Name: 'Charting', Toolbars: ['Charting']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Charting: {
ChartDefinitions: [
{
Name: 'Top Frameworks',
Model: {
modelType: 'range',
chartId: 'frameworks-pie',
chartType: 'pie',
chartThemeName: 'ag-vivid-dark',
chartOptions: {
pie: {
background: {
visible: true,
},
padding: {
top: 20,
right: 20,
bottom: 20,
left: 20,
},
title: {
enabled: false,
},
subtitle: {
enabled: false,
},
legend: {
enabled: true,
position: 'right',
},
tooltip: {
enabled: true,
},
series: {
tooltip: {
enabled: true,
},
showInLegend: true,
cursor: 'default',
title: {
enabled: false,
},
calloutLabel: {
enabled: true,
},
sectorLabel: {
enabled: true,
},
calloutLine: {
length: 10,
strokeWidth: 2,
},
},
},
},
cellRange: {
rowStartIndex: 0,
rowEndIndex: 4,
columns: ['name', 'github_stars'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
{
Name: 'Issues & PRs',
Model: {
modelType: 'range',
chartId: 'issues-bar',
chartType: 'normalizedBar',
chartThemeName: 'ag-vivid-dark',
chartOptions: {
bar: {
background: {
visible: true,
},
padding: {top: 20, right: 20, bottom: 20, left: 20},
title: {
enabled: false,
},
subtitle: {
enabled: false,
},
legend: {
enabled: true,
position: 'right',
spacing: 20,
},
tooltip: {
enabled: true,
},
},
},
cellRange: {
rowStartIndex: 0,
rowEndIndex: 9,
columns: [
'name',
'open_issues_count',
'closed_issues_count',
'closed_pr_count',
'open_pr_count',
],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'github_stars',
'name',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'github_watchers',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'has_projects',
'has_pages',
'week_issue_change',
],
ColumnSorts: [{ColumnId: 'github_stars', SortOrder: 'Desc'}],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
## Multiple Charts in a Location
By default AdapTable will display one chart in each provided Location.
This means that loading a new chart will displace any currently displayed Chart.
This behaviour can be changed by setting `chartsDisplay` in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) to 'multiple'.
When this property is set, charts are **appended** to the Div.
- To place multiple charts in a container, it needs a fixed height - e.g. `max-height` or `display: flex`
- Without this the charts will grow inside the Div infinitely
**Example: Multiple Charts in Location**
Showing multiple AG Grid Charts in a Div
- This example demonstrates how to show multiple charts in the same location:
- The `chartsDisplay` property in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) has been set to 'multiple'
- An `Above Grid` Chart Container has been provided, together with 2 Chart Definitions
- The Chart Container has `display: flex` to allow multiple Charts to be shown
- In the [Adaptable Ready Event](https://www.adaptabletools.com/docs/getting-started-adaptable-ready/index.md) we use [Charting API](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) methods to display the 2 Charts in the Container
### Expand to see how the Charts were displayed
Charting Options is defined as this:
```ts
chartingOptions: {
saveChartBehaviour: 'manual',
chartContainers: [
{
name: 'Above Grid',
element: topChartContainer,
chartsDisplay: 'multiple',
},
],
},
```
The AdaptableReady event contains this code:
```ts
const adaptableApi: AdaptableApi = readyInfo.adaptableApi;
const topChartContainer = document.getElementById('demoOutputAbove') as HTMLDivElement;
const chartDefs: ChartDefinition[] = adaptableApi.chartingApi.getChartDefinitions();
adaptableApi.chartingApi.showChartDefinition(chartDefs[0], topChartContainer);
adaptableApi.chartingApi.showChartDefinition(chartDefs[1], topChartContainer);
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Multiple Charts',
chartingOptions: {
chartContainers: [
{
name: 'Above Grid',
element: '#demoOutputAbove',
chartsDisplay: 'multiple',
},
],
},
initialState: {
Dashboard: {
Tabs: [{Name: 'Charting', Toolbars: ['Charting']}],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Charting: {
ChartDefinitions: [
{
Name: 'Top Frameworks',
Model: {
modelType: 'range',
chartId: 'frameworks-pie',
chartType: 'pie',
chartThemeName: 'ag-vivid-dark',
chartOptions: {
pie: {
background: {
visible: true,
},
padding: {
top: 20,
right: 20,
bottom: 20,
left: 20,
},
title: {
enabled: false,
},
subtitle: {
enabled: false,
},
legend: {
enabled: true,
position: 'right',
},
tooltip: {
enabled: true,
},
series: {
tooltip: {
enabled: true,
},
showInLegend: true,
title: {
enabled: false,
},
calloutLabel: {
enabled: true,
},
sectorLabel: {
enabled: true,
},
calloutLine: {
length: 10,
strokeWidth: 2,
},
},
},
},
cellRange: {
rowStartIndex: 0,
rowEndIndex: 4,
columns: ['name', 'github_stars'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
{
Name: 'Issues & PRs',
Model: {
modelType: 'range',
chartId: 'issues-bar',
chartType: 'normalizedBar',
chartThemeName: 'ag-vivid-dark',
chartOptions: {
bar: {
background: {
visible: true,
},
padding: {top: 20, right: 20, bottom: 20, left: 20},
title: {
enabled: false,
},
subtitle: {
enabled: false,
},
legend: {
enabled: true,
position: 'right',
},
tooltip: {
enabled: true,
},
series: {
tooltip: {
enabled: true,
},
showInLegend: true,
},
navigator: {
enabled: false,
},
},
},
cellRange: {
rowStartIndex: 0,
rowEndIndex: 9,
columns: [
'name',
'open_issues_count',
'closed_issues_count',
'closed_pr_count',
'open_pr_count',
],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'github_stars',
'name',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'github_watchers',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'has_projects',
'has_pages',
'week_issue_change',
],
ColumnSorts: [{ColumnId: 'github_stars', SortOrder: 'Desc'}],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {AdaptableReadyInfo, ChartDefinition} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
const topChartContainer = document.getElementById(
'demoOutputAbove'
) as HTMLDivElement;
const chartDefs: ChartDefinition[] =
adaptableApi.chartingApi.getChartDefinitions();
adaptableApi.chartingApi.showChartDefinition(chartDefs[0], topChartContainer);
adaptableApi.chartingApi.showChartDefinition(chartDefs[1], topChartContainer);
};
```
```css
#demoOutputAbove {
display: flex;
}
```
### `agGridContainerName`
Name of AG Grid Chart Container
Multiple containers can be provided for charts at design-time.
When this happens the container provided by AG Grid (which appears in the middle of the screen) is added to the list.
By default this container is entitled "AG Grid Window", but this property allows this container to be renamed.
```ts {4}
// Rename the AG Grid container to "Grid"
const adaptableOptions: AdaptableOptions = {
chartingOptions: {
agGridContainerName: "Grid"
}
}
```
### `chartContainers`
Locations to display saved Charts
[`ChartContainer[]`](https://www.adaptabletools.com/docs/reference/chartcontainer.md)
Defines locations where AG Grid charts which have been saved into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) can be displayed.
These locations, if provided, appear in a dropdown in the Charting [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) and [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md).
This **doesn't** override the `createChartContainer` property in AG Grid's GridOptions
The [`ChartContainer`](https://www.adaptabletools.com/docs/reference/chartcontainer.md) object is defined as follows:
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [chartsDisplay](https://www.adaptabletools.com/docs/reference/chartcontainer.md#chartsdisplay) | `'single' \| 'multiple'` | Whether 1 or more Charts can be displayed in same location | 'single' |
| [element](https://www.adaptabletools.com/docs/reference/chartcontainer.md#element) | `HTMLElement \| string` | Location - can be HTMLElement or CSS Selector | |
| [name](https://www.adaptabletools.com/docs/reference/chartcontainer.md#name) | `string` | Name of Container's Location - used in Dropdowns | |
Assuming you created your page like this:
```html
```
You could define Chart Containers as follows:
```ts {9}
// Get the HTML Element for chart-container
const topChartContainer = document.getElementById('top-chart-container') as HTMLDivElement;
// Supply 2 Containers:
// 1. Placed above Grid and defined as an HTML Element, allowing multiple Charts
// 2. Placed below the Grid and referenced by name
const adaptableOptions: AdaptableOptions = {
chartingOptions: {
chartContainers: [
{
name: 'Above Grid',
element: topChartContainer,
chartsDisplay: 'multiple'
},
{
name: 'Below Grid',
element: '#chart-container-bottom',
},
],
},
}
```
### `saveChartBehaviour`
Behaviour for saving Charts into AdapTable State
By default AdapTable will not save any AG Grid charts the user creates into AdapTable State.
This property offers 3 options:
- `auto`: all created charts are saved automatically in Adaptable state
- `manual`: a popup is shown to the user to save the chart
- `none`: charts are not saved
```ts {4}
// Tell AdapTable to display a popup each time a new Chart is created
const adaptableOptions: AdaptableOptions = {
chartingOptions: {
saveChartBehaviour: 'manual',
},
}
```
---
# External Chart Libraries
Canonical page: https://www.adaptabletools.com/docs/handbook-charts-external
- Most charting users access the charts provided by AG Grid
- However AdapTable can work with any charting library
AdapTable integrates closely with AG Grid's charts, and is the most common charting use case.
But AdapTable can be used in conjunction with any charting library.
AdapTable's rich [Adaptable API](https://www.adaptabletools.com/docs/technical-reference-adaptable-api/index.md) and the many [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md) make it easier to synchronise data in the Grid with your preferred Charting library.
- We are keen to add additional support for external charting and to meet all use cases
- So please contact us if there is specific functionality that you would like us to make available
**Example: External Charts Library**
Using external charts libraries
- This demo shows how to use the [Highcharts](https://www.highcharts.com/) Charting library from AdapTable
- From any valid selection (one string and one numeric) column we are able to use the Context Menu to create 3 different chart types:
- Pie Chart
- Line Chart
- Bar Chart
- Select a range that includes a numeric and a string column (we pre-select a range using the [Grid API](https://www.adaptabletools.com/docs/handbook-managing-grid-data/index.md))
- Create a **Highchart** by selecting `Show Charts` from the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) (the first item, and only enabled if there is a valid selection) and choose a Chart type
```ts
import {
AdaptableOptions,
ContextMenuContext,
CustomContextMenuContext,
SelectedCellInfo,
UserContextMenuItem,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
import {chartIcon, pieIcon, lineChartIcon, barChartIcon} from './icons';
import {charginService} from './chartingService';
/**
* Selection is valid only when:
* - two columns are selected
* - one is numeric and the other text
*/
const isSelectionValidForSimpleCharts = (selection: SelectedCellInfo) => {
// Two columns need to be selected
if (selection.columns.length !== 2) {
return false;
}
// At least one is numeric
const oneColumnIsNumeric =
selection.columns.filter(column => column.dataType === 'number').length ===
1;
if (!oneColumnIsNumeric) {
return false;
}
// At least one text
const oneColumnIsText =
selection.columns.filter(column => column.dataType === 'text').length === 1;
if (!oneColumnIsText) {
return false;
}
return true;
};
const contextMenuOptions: AdaptableOptions['contextMenuOptions'] = {
customContextMenu: (context: CustomContextMenuContext) => {
const {defaultAgGridMenuStructure, defaultAdaptableMenuStructure} = context;
const chartMenuItem: UserContextMenuItem = {
menuType: 'User',
label: 'Show Charts',
icon: {
element: chartIcon,
},
subMenuItems: [
{
menuType: 'User',
label: 'Pie Chart',
icon: {element: pieIcon},
onClick: (menuContext: ContextMenuContext) => {
const selection =
menuContext.adaptableApi.gridApi.getSelectedCellInfo();
charginService.showPieChart(selection);
},
},
{
menuType: 'User',
label: 'Line Chart',
icon: {element: lineChartIcon},
onClick: (menuContext: ContextMenuContext) => {
const selection =
menuContext.adaptableApi.gridApi.getSelectedCellInfo();
charginService.showLineChart(selection);
},
},
{
menuType: 'User',
label: 'Bar Chart',
icon: {element: barChartIcon},
onClick: (menuContext: ContextMenuContext) => {
const selection =
menuContext.adaptableApi.gridApi.getSelectedCellInfo();
charginService.showBarChart(selection);
},
},
],
};
return [
chartMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
};
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Using External Charts',
contextMenuOptions,
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Charting',
Toolbars: ['Layout'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'github_watchers',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
// enable charts and set a theme
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
export const chartIcon = `
`;
export const pieIcon = `
`;
export const lineChartIcon = `
`;
export const barChartIcon = `
`;
```
```ts
import {SelectedCellInfo} from '@adaptabletools/adaptable';
import * as Highcharts from 'highcharts';
const container = 'demoOutputAbove';
/**
* It goes over the selected cells and groupes them in two sets:
* - categories: the values of the string column (if there is one)
* - value: the numeric values
*/
const getCategoriesAndValuesFromSelection = (selection: SelectedCellInfo) => {
const [col1, col2] = selection.columns;
// Select the string column as the category column
const categoryColumn = col1.dataType === 'text' ? col1 : col2;
const valueColumn = col1.dataType === 'number' ? col1 : col2;
// Group the selected cells in sets of [category-name, value]
const categoryValueSets: [string | number, number][] = [];
for (let categoryCell of selection.gridCells) {
if (categoryCell.column.columnId === categoryColumn.columnId) {
// find corresponding value
const valueCell = selection.gridCells.find(localGridCell => {
return (
localGridCell.rowNode.id === categoryCell.rowNode.id &&
// and not the same column
localGridCell.column.columnId !== categoryCell.column.columnId
);
});
if (valueCell) {
categoryValueSets.push([categoryCell.rawValue, valueCell.rawValue]);
}
}
}
const categories = categoryValueSets.map(([category]) => category);
const values = categoryValueSets.map(([category, value]) => value);
return {categories, values, categoryColumn, valueColumn, categoryValueSets};
};
export const charginService = {
showLineChart: (selection: SelectedCellInfo) => {
const {categories, values, categoryColumn, valueColumn} =
getCategoriesAndValuesFromSelection(selection);
// @ts-ignore
Highcharts.chart(container, {
title: {
text: 'Dynamic Simple Line Chart',
align: 'left',
},
yAxis: {
title: {
text: categoryColumn?.friendlyName,
},
},
xAxis: {
categories,
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
},
plotOptions: {
series: {
label: {
connectorAllowed: false,
},
},
},
series: [
{
name: `${categoryColumn?.friendlyName} and ${valueColumn?.friendlyName}`,
data: values,
},
],
responsive: {
rules: [
{
condition: {
maxWidth: 500,
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom',
},
},
},
],
},
});
},
showPieChart: (selection: SelectedCellInfo) => {
const {categoryColumn, categoryValueSets} =
getCategoriesAndValuesFromSelection(selection);
const series = categoryValueSets.map(([category, value]) => ({
name: category,
y: value,
}));
// @ts-ignore
Highcharts.chart(container, {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie',
},
title: {
text: 'Dynamic Simple Pie Chart',
align: 'left',
},
tooltip: {
pointFormat: '{series.name}: {point.percentage:.1f}%',
},
accessibility: {
point: {
valueSuffix: '%',
},
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '{point.name}: {point.percentage:.1f} %',
},
},
},
series: [
{
name: categoryColumn.friendlyName,
colorByPoint: true,
data: series,
},
],
});
},
showBarChart: (selection: SelectedCellInfo) => {
const {categoryColumn, valueColumn, categoryValueSets} =
getCategoriesAndValuesFromSelection(selection);
const series: any = [
{
name: categoryColumn.friendlyName,
data: categoryValueSets,
},
];
Highcharts.chart(container, {
chart: {
type: 'column',
},
title: {
text: 'Dynamic Bar Chart',
},
xAxis: {
type: 'category',
},
yAxis: {
title: {
text: valueColumn.friendlyName,
},
},
series,
});
},
};
```
```ts
import {
AdaptableApi,
AdaptableReadyInfo,
GridCellRange,
} from '@adaptabletools/adaptable';
const CHART_IN_LAYOUT_KEY = 'chartInLayout';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
const api = adaptableApi;
const rowIndexCellRange: GridCellRange = {
columnIds: ['name', 'github_stars'],
rowIndexStart: 0,
rowIndexEnd: 8,
};
api.gridApi.selectCellRange(rowIndexCellRange);
};
```
## Saving Charts
External charts can also be saved into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
Similar to the [configuration for AG Grid Charts](https://www.adaptabletools.com/docs/handbook-charts-configuring/index.md), External Charts can be:
- defined in Initial Adaptable State (i.e. configured at design-time)
- created at run-time and then saved into State to be available when the application restarts
- be displayed in custom locations provided by the users
**Example: Saving External Charts**
Using external charts libraries with Adaptable State
- This example shows how External Charts can be saved into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) and then displayed in AdapTable
- 2 external (Highcharts) charts are defined in [Initial Adaptable State](https://www.adaptabletools.com/docs/technical-reference-initial-state/index.md):
- Github Stars Line Chart
- Frameworks Pie
- 2 custom Charting Containers are defined in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md):
- Above Grid
- Below Grid
- In the Charting Toolbar select an External Chart and a Container
- Click the `Show Chart` (Eye icon) button to display / hide the Charts
```ts
import {
AdaptableOptions,
ContextMenuContext,
CustomContextMenuContext,
SelectedCellInfo,
UserContextMenuItem,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
import {chartIcon, pieIcon, lineChartIcon, barChartIcon} from './icons';
import {ChartingService, ChartModel} from './chartingService';
const chartingService = new ChartingService();
/**
* Selection is valid only when:
* - two columns are selected
* - one is numeric and the other text
*/
const isSelectionValidForSimpleCharts = (selection: SelectedCellInfo) => {
// Two columns need to be selected
if (selection.columns.length !== 2) {
return false;
}
// At least one is numeric
const oneColumnIsNumeric =
selection.columns.filter(column => column.dataType === 'number').length ===
1;
if (!oneColumnIsNumeric) {
return false;
}
// At least one text
const oneColumnIsText =
selection.columns.filter(column => column.dataType === 'text').length === 1;
if (!oneColumnIsText) {
return false;
}
return true;
};
const contextMenuOptions: AdaptableOptions['contextMenuOptions'] = {
customContextMenu: (context: CustomContextMenuContext) => {
const {defaultAgGridMenuStructure, defaultAdaptableMenuStructure} = context;
const chartMenuItem: UserContextMenuItem = {
menuType: 'User',
label: 'Show Charts',
icon: {
element: chartIcon,
},
subMenuItems: [
{
menuType: 'User',
label: 'Pie Chart',
icon: {element: pieIcon},
onClick: (menuContext: ContextMenuContext) => {
const selection =
menuContext.adaptableApi.gridApi.getSelectedCellInfo();
const chartModel = chartingService.showPieChart(selection);
menuContext.adaptableApi.chartingApi.addExternalChartDefinition({
Name: 'Pie Chart',
Data: chartModel,
});
},
},
{
menuType: 'User',
label: 'Line Chart',
icon: {element: lineChartIcon},
onClick: (menuContext: ContextMenuContext) => {
const selection =
menuContext.adaptableApi.gridApi.getSelectedCellInfo();
const chartModel = chartingService.showLineChart(selection);
menuContext.adaptableApi.chartingApi.addExternalChartDefinition({
Name: 'Chart-Name',
Data: chartModel,
});
},
},
{
menuType: 'User',
label: 'Bar Chart',
icon: {element: barChartIcon},
onClick: (menuContext: ContextMenuContext) => {
const selection =
menuContext.adaptableApi.gridApi.getSelectedCellInfo();
const chartModel = chartingService.showBarChart(selection);
menuContext.adaptableApi.chartingApi.addExternalChartDefinition({
Name: 'Pie Chart',
Data: chartModel,
});
},
},
],
};
return [
chartMenuItem,
'-',
...defaultAgGridMenuStructure,
'-',
...defaultAdaptableMenuStructure,
];
},
};
const chartingOptions: AdaptableOptions['chartingOptions'] = {
chartContainers: [
{
name: 'Above Grid',
element: 'demoOutputAbove',
},
{
name: 'Below Grid',
element: 'demoOutputBelow',
},
],
externalChartingOptions: {
/**
* This indicates to Adaptable if a chart is rendered or not.
* This status is used to call the corect handlers when showing/hiding a chart.
*/
isChartOpened: ({adaptableApi, chartDefinition}) => {
const chartModel = chartDefinition?.Data as ChartModel;
return chartingService.isChartOpened(chartModel.chartId);
},
/**
* This is called when the user clicks the eye button next to the chart.
*/
onHideChart: ({adaptableApi, chartDefinition}) => {
const chartModel = chartDefinition.Data as ChartModel;
chartingService.destroyChart(chartModel.chartId);
},
/**
* This is called when the user clicks the eye button next to the chart.
*/
onShowChart: ({adaptableApi, chartDefinition, container}) => {
const chartModel = chartDefinition.Data as ChartModel;
chartingService.restoreChart(chartModel, container?.element);
},
/**
* This is called when the user deltes a chart from from adaptable.
* We may want to hide the chart when it is deleted.
*/
onDeleteChart: ({adaptableApi, chartDefinition}) => {
const chartModel = chartDefinition.Data as ChartModel;
if (chartingService.isChartOpened(chartModel.chartId)) {
chartingService.destroyChart(chartModel.chartId);
}
},
/**
* Preview charts are transient charts, these charts should not be saved in state.
* They are rendered in preivews.
*
* The returned object is passed to 'onHideChart'.
* The returned object needs to have enough information to identify the instance of the chart.
* This is important because we want to destory the chart when the preview is closed.
*/
onPreviewChart: ({adaptableApi, chartDefinition, container}) => {
const chartModel = chartDefinition.Data as ChartModel;
return {
Name: 'Preview Chart',
Data: chartingService.previewChart(chartModel, container?.element),
};
},
},
};
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Saving External Charts',
contextMenuOptions,
chartingOptions,
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Charting',
Toolbars: ['Charting'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'github_watchers',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
AutoSizeColumns: true,
},
],
},
Charting: {
ExternalChartDefinitions: [
{
Name: 'Github Stars Line chart',
Data: {
options: {
chart: {
type: 'line',
},
title: {
text: 'Dynamic Simple Line Chart',
align: 'left',
},
yAxis: {
title: {
text: 'Name',
},
},
xAxis: {
categories: [
'react',
'angular',
'vue',
'svelte',
'alpine',
'lit',
'stimulus',
'ember.js',
'stencil',
],
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
},
plotOptions: {
series: {
label: {
connectorAllowed: false,
},
},
},
series: [
{
name: 'Name and GitHub Stars',
data: [
179429, 78348, 191435, 53935, 19338, 9752, 11049, 22093,
9884,
],
},
],
responsive: {
rules: [
{
condition: {
maxHeight: 300,
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom',
},
},
_id: 'highcharts-c73e53c-14',
},
],
},
},
chartId: 'CHART_ID_1696840189274',
},
Uuid: '80da73bd-75e4-4371-a7f9-7ba518cb9113',
},
{
Name: 'Frameworks Pie chart',
Data: {
options: {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie',
},
title: {
text: 'Dynamic Simple Pie Chart',
align: 'left',
},
tooltip: {
pointFormat: '{series.name}: {point.percentage:.1f}%',
},
accessibility: {
point: {
valueSuffix: '%',
},
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '{point.name}: {point.percentage:.1f} %',
},
},
},
series: [
{
name: 'Name',
colorByPoint: true,
data: [
{
name: 'angular',
y: 78348,
},
{
name: 'vue',
y: 191435,
},
{
name: 'svelte',
y: 53935,
},
{
name: 'alpine',
y: 19338,
},
{
name: 'lit',
y: 9752,
},
{
name: 'stimulus',
y: 11049,
},
{
name: 'ember.js',
y: 22093,
},
{
name: 'stencil',
y: 9884,
},
{
name: 'solid',
y: 13119,
},
],
},
],
},
chartId: 'CHART_ID_1696840216341',
},
Uuid: '19f72754-c322-4b23-b4f5-2fca05a0132b',
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
// enable charts and set a theme
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
export const chartIcon = `
`;
export const pieIcon = `
`;
export const lineChartIcon = `
`;
export const barChartIcon = `
`;
```
```ts
import {SelectedCellInfo} from '@adaptabletools/adaptable';
import * as Highcharts from 'highcharts';
/**
* This service is an example on how one would integrate an external charting library with Adaptable.
*
* It is a statefull service, it keep track of the chart instances and their location.
* Using this state it knows which charts are open and allows it to control them.
*/
const container = 'demoOutputAbove';
/**
* This is used to generate unique ids for the charts.
*/
const getUniqueID = () => {
return `CHART_ID_${Date.now()}`;
};
/**
* Prepares data for the charts.
*
* Takes the selection and returns the data grouped in two sets:
* - categories: the text column values
* - values: the numeric values
*/
const getCategoriesAndValuesFromSelection = (selection: SelectedCellInfo) => {
const [col1, col2] = selection.columns;
// Select the string column as the category column
const categoryColumn = col1.dataType === 'text' ? col1 : col2;
const valueColumn = col1.dataType === 'number' ? col1 : col2;
// Group the selected cells in sets of [category-name, value]
const categoryValueSets: [string, number][] = [];
for (let categoryCell of selection.gridCells) {
if (categoryCell.column.columnId === categoryColumn.columnId) {
// find corresponding value
const valueCell = selection.gridCells.find(localGridCell => {
return (
localGridCell.rowNode.id === categoryCell.rowNode.id &&
// and not the same column
localGridCell.column.columnId !== categoryCell.column.columnId
);
});
if (valueCell) {
categoryValueSets.push([categoryCell.rawValue, valueCell.rawValue]);
}
}
}
const categories = categoryValueSets.map(([category]) => category);
const values = categoryValueSets.map(([category, value]) => value);
return {categories, values, categoryColumn, valueColumn, categoryValueSets};
};
/**
* This model is saved in adaptable state. This is all one needs to manage chart persistence.
*
*/
export type ChartModel = {
options: Highcharts.Options;
/**
* The chartId allows us to know if a persisted chart is opened or not.
* When a chart is created a unique id is generated.
*/
chartId: string;
};
export class ChartingService {
/**
* This map helps us to keep track of the chart instances.
* To know which chart is opened in which container.
*/
private chartInstances: Record<
string,
{
location: string | HTMLElement;
Instance: Highcharts.Chart;
}
> = {};
// CHART INSTANCES MANAGEMENT
/**
* Checks if a chart is opened.
* We consider that a chart instance can be open in only one location.
*
* It checkis the the chart id is in the chartInstances map.
*
* @param chartId unique chart id
* @returns boolean
*/
public isChartOpened(chartId: string): boolean {
return !!this.getChart(chartId);
}
/**
* Destroys a chart instance.
*
* @param chartId unique chart id
*/
destroyChart(chartId: string) {
const chartInstance = this.getChart(chartId);
if (chartInstance) {
chartInstance.Instance?.destroy?.();
delete this.chartInstances[chartId];
}
}
/**
*
* @param chartId unique chart id
* @returns
*/
private getChart(
chartId: string
): {location: string | HTMLElement; Instance: Highcharts.Chart} | undefined {
return this.chartInstances[chartId];
}
// CREATE CHARTS
/**
* An internal method to create charts and keep track of them.
*/
private createChart(
chartOptions: Highcharts.Options,
options?: {
location?: string | HTMLElement;
chartId?: string;
isPreview?: boolean;
}
) {
const location = options?.location ?? container;
// For now just close all charts before opening a new one.
// more complex logic needs to be implemented to allow multiple charts.
this.closeAllChartsAtLocation(location);
const chartId = options?.chartId ?? getUniqueID();
const chartInstance = Highcharts.chart(location, chartOptions);
this.chartInstances[chartId] = {
location,
Instance: chartInstance,
};
return {
options: chartOptions,
chartId,
};
}
/**
* It closes all charts at a given location.
* This service supports only one chart per location.
*
* @param location chart location
*/
private closeAllChartsAtLocation(location: string | HTMLElement) {
Object.entries(this.chartInstances).forEach(
([chartId, {Instance, location: instanceLocation}]) => {
if (instanceLocation === location) {
if (Instance.destroy) {
try {
Instance.destroy?.();
} catch (e) {
console.error('Failed to destroy chart with id: ', chartId);
}
}
delete this.chartInstances[chartId];
}
}
);
}
/**
* Recreates previously created charts.
*
* @param chartModel holds information about previous created chart
* @param location location where the chart should be rendered to
*/
restoreChart(chartModel: ChartModel, location?: string | HTMLElement) {
const {options, chartId} = chartModel;
return this.createChart(options, {chartId, location});
}
/**
* The difference between this and restore is that it ignore the chartId.
* This means it creates a new chart. This allows us to preview the chart
*
* @param chartModel holds information about previous created chart
* @param location location where the chart should be rendered to
*/
previewChart(chartModel: ChartModel, location?: string | HTMLElement) {
const {options} = chartModel;
return this.createChart(options, {location});
}
/**
* Creates a line chart and returns the chart model.
*/
public showLineChart(selection: SelectedCellInfo): ChartModel {
const {categories, values, categoryColumn, valueColumn} =
getCategoriesAndValuesFromSelection(selection);
let valuesAny: any = values;
const chartConfig: Highcharts.Options = {
chart: {
type: 'line',
// height: 200,
},
title: {
text: 'Dynamic Simple Line Chart',
align: 'left',
},
yAxis: {
title: {
text: categoryColumn?.friendlyName,
},
},
xAxis: {
categories,
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
},
plotOptions: {
series: {
label: {
connectorAllowed: false,
},
},
},
series: [
//@ts-ignore
{
name: `${categoryColumn?.friendlyName} and ${valueColumn?.friendlyName}`,
// @ts-ignore
data: values,
},
],
responsive: {
rules: [
{
condition: {
maxHeight: 300,
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom',
},
},
},
],
},
};
return this.createChart(chartConfig);
}
/**
* Creates a pie chart and returns the chart model.
*/
public showPieChart(selection: SelectedCellInfo): ChartModel {
const {categoryColumn, categoryValueSets} =
getCategoriesAndValuesFromSelection(selection);
const series = categoryValueSets.map(([category, value]) => ({
name: category,
y: value,
}));
const config: Highcharts.Options = {
chart: {
// @ts-ignore
plotBackgroundColor: null,
// @ts-ignore
plotBorderWidth: null,
plotShadow: false,
type: 'pie',
// height: 200,
},
title: {
text: 'Dynamic Simple Pie Chart',
align: 'left',
},
tooltip: {
pointFormat: '{series.name}: {point.percentage:.1f}%',
},
accessibility: {
point: {
valueSuffix: '%',
},
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '{point.name}: {point.percentage:.1f} %',
},
},
},
series: [
{
name: categoryColumn.friendlyName,
colorByPoint: true,
data: series,
} as any,
],
};
return this.createChart(config);
}
/**
* Creates a bar chart and returns the chart model.
*/
public showBarChart(selection: SelectedCellInfo): ChartModel {
const {categoryColumn, valueColumn, categoryValueSets} =
getCategoriesAndValuesFromSelection(selection);
const config: Highcharts.Options = {
chart: {
type: 'column',
// height: 200,
},
title: {
text: 'Dynamic Bar Chart',
},
xAxis: {
type: 'category',
},
yAxis: {
title: {
text: valueColumn.friendlyName,
},
},
series: [
{
name: categoryColumn.friendlyName,
data: categoryValueSets,
} as any,
],
};
return this.createChart(config);
}
}
```
---
# Charts Technical Reference
Canonical page: https://www.adaptabletools.com/docs/handbook-charts-technical-reference
- The Chart Changed Event fires when Charting State changes
- Charting Initial Adaptable State contains chart definitions saved into AdapTable State
- Charting API contains chart-related functions
- Charting Options contains charting properties
## Chart Changed Event
The [Chart Changed Event](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) fires whenever there are any modifications to any open [Charts](https://www.adaptabletools.com/docs/handbook-charts/index.md).
### ChartChangedInfo
The event comprises a single [`ChartChangedInfo`](https://www.adaptabletools.com/docs/reference/chartchangedinfo.md) object which lists the currently opened Charts:
| Property | Type | Description |
| --- | --- | --- |
| [chartingOpenState](https://www.adaptabletools.com/docs/reference/chartchangedinfo.md#chartingopenstate) | [`ChartingOpenState`](https://www.adaptabletools.com/docs/reference/chartingopenstate.md) | Details of Open Charts |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/chartchangedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
This object contains a collection of [`ChartDisplayedInfo`](https://www.adaptabletools.com/docs/reference/chartdisplayedinfo.md) objects which contains details of displayed Charts:
| Property | Type | Description |
| --- | --- | --- |
| [chartDefinition](https://www.adaptabletools.com/docs/reference/chartdisplayedinfo.md#chartdefinition) | [`ChartDefinition`](https://www.adaptabletools.com/docs/reference/chartdefinition.md) | Definition of the Chart |
| [containerName](https://www.adaptabletools.com/docs/reference/chartdisplayedinfo.md#containername) | `string \| null` | Container where Chart is displayed |
| [isOpen](https://www.adaptabletools.com/docs/reference/chartdisplayedinfo.md#isopen) | `boolean` | Whether Chart is Open |
### Event Subscription
Subscribing to the Event is done the same way as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md):
```ts
api.eventApi.on('ChartChanged', (eventInfo: ChartChangedInfo) => {
// do something with the info
});
```
------
## Charting State
The Chart section of Adaptable State contains a single `ChartDefinitions` collection:
| Property | Type | Description |
| --- | --- | --- |
| [ChartDefinitions](https://www.adaptabletools.com/docs/reference/chartingstate.md#chartdefinitions) | [`ChartDefinition`](https://www.adaptabletools.com/docs/reference/chartdefinition.md)`[]` | Wrappers around AG Grid Chart Models |
| [ExternalChartDefinitions](https://www.adaptabletools.com/docs/reference/chartingstate.md#externalchartdefinitions) | `ExternalChartDefinition[]` | Definitions of External Charts |
### Chart Definition Object
A [`ChartDefinition`](https://www.adaptabletools.com/docs/reference/chartdefinition.md) simply wraps an AG Grid Charting Model:
| Property | Type | Description |
| --- | --- | --- |
| [Model](https://www.adaptabletools.com/docs/reference/chartdefinition.md#model) | `ChartModel` | AG Grid Chart Model |
| [Name](https://www.adaptabletools.com/docs/reference/chartdefinition.md#name) | `string` | Unique name of the chart (used in UI and layout references, like Layout names) |
| [IsReadOnly](https://www.adaptabletools.com/docs/reference/chartdefinition.md#isreadonly) | `boolean` | Sets Entity to ReadOnly (overwriting a Strategy Entitlement of 'Full') |
------
## Charting Options
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [agGridContainerName](https://www.adaptabletools.com/docs/reference/chartingoptions.md#aggridcontainername) | `string` | Name of AG Grid Chart Container | 'AG Grid Window' |
| [chartContainers](https://www.adaptabletools.com/docs/reference/chartingoptions.md#chartcontainers) | [`ChartContainer`](https://www.adaptabletools.com/docs/reference/chartcontainer.md)`[]` | Locations to display saved Charts | |
| [externalChartingOptions](https://www.adaptabletools.com/docs/reference/chartingoptions.md#externalchartingoptions) | [`ExternalChartingOptions`](https://www.adaptabletools.com/docs/reference/externalchartingoptions.md) | Set of properties for managing behaviour of external (i.e non AG Grid) charts | |
| [restoreChartsOnReady](https://www.adaptabletools.com/docs/reference/chartingoptions.md#restorechartsonready) | `boolean \| 'all' \| string[]` | Opens persisted AG Grid charts when AdapTable is ready. - `true` or `'all'`: all charts in `Charting.ChartDefinitions` - `string[]`: chart names to open (matches each definition's `Name` property) | undefined (no charts opened automatically) |
| [saveChartBehaviour](https://www.adaptabletools.com/docs/reference/chartingoptions.md#savechartbehaviour) | [`SaveChartBehaviour`](https://www.adaptabletools.com/docs/reference/savechartbehaviour.md) | Behaviour for saving Charts: auto, manual (via popup) or none | 'none' |
### External Charting Options
| Property | Type | Description |
| --- | --- | --- |
| [isChartOpened](https://www.adaptabletools.com/docs/reference/externalchartingoptions.md#ischartopened) | `(context: `[`ExternalChartingContext`](https://www.adaptabletools.com/docs/reference/externalchartingcontext.md)`) => boolean` | Needs to be implemented to specify if Chart is opened; used to set Show Button's highlighting |
| [onDeleteChart](https://www.adaptabletools.com/docs/reference/externalchartingoptions.md#ondeletechart) | `(context: `[`ExternalChartingContext`](https://www.adaptabletools.com/docs/reference/externalchartingcontext.md)`) => void` | Called when User deletes a persisted Chart |
| [onHideChart](https://www.adaptabletools.com/docs/reference/externalchartingoptions.md#onhidechart) | `(context: `[`ExternalChartingContext`](https://www.adaptabletools.com/docs/reference/externalchartingcontext.md)`) => void` | Called when User clicks on Hide button next to Chart |
| [onPreviewChart](https://www.adaptabletools.com/docs/reference/externalchartingoptions.md#onpreviewchart) | `(context: `[`ExternalChartingContext`](https://www.adaptabletools.com/docs/reference/externalchartingcontext.md)`) => ExternalChartDefinition` | Shows Chart in Settings Panel preview (not saved into State); returned definition will be passed to 'onHideChart' when Preview closes |
| [onShowChart](https://www.adaptabletools.com/docs/reference/externalchartingoptions.md#onshowchart) | `(context: `[`ExternalChartingContext`](https://www.adaptabletools.com/docs/reference/externalchartingcontext.md)`) => void` | Called when User clicks on Show button next to Chart |
------
## Charting API
The [Charting API](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) section of AdapTable API includes a small number of chart-related functions.
These make it easy to save and retrieves charts from [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
In practice this is more likely to be done at run-time but charts can be defined at design time if required
Charting API includes these functions:
| Method | Returns | Description |
| --- | --- | --- |
| [addChartDefinition(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#addchartdefinition) | `void` | Add new Chart |
| [addExternalChartDefinition(chartDef, options)](https://www.adaptabletools.com/docs/reference/chartingapi.md#addexternalchartdefinition) | `void` | Add new external chart definition |
| [closeChartDefinition(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#closechartdefinition) | `void` | Close Chart definition |
| [deleteExternalChartDefinition(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#deleteexternalchartdefinition) | `void` | Delete external chart definition |
| [editChartDefinition(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#editchartdefinition) | `void` | Edit existing Chart |
| [editExternalChartDefinition(chartDef)](https://www.adaptabletools.com/docs/reference/chartingapi.md#editexternalchartdefinition) | `void` | Edit existing external chart definition |
| [getChartDefinitionByName(name)](https://www.adaptabletools.com/docs/reference/chartingapi.md#getchartdefinitionbyname) | [`ChartDefinition`](https://www.adaptabletools.com/docs/reference/chartdefinition.md)` \| undefined` | Retrieves Chart definition by name |
| [getChartDefinitionByUuid(uuid)](https://www.adaptabletools.com/docs/reference/chartingapi.md#getchartdefinitionbyuuid) | [`ChartDefinition`](https://www.adaptabletools.com/docs/reference/chartdefinition.md)` \| undefined` | Retrieves Chart definition by uuid |
| [getChartDefinitions()](https://www.adaptabletools.com/docs/reference/chartingapi.md#getchartdefinitions) | [`ChartDefinition`](https://www.adaptabletools.com/docs/reference/chartdefinition.md)`[]` | Retrieves all adaptable Chart definitions |
| [getChartingOpenState()](https://www.adaptabletools.com/docs/reference/chartingapi.md#getchartingopenstate) | [`ChartingOpenState`](https://www.adaptabletools.com/docs/reference/chartingopenstate.md) | Get info about all saved charts, incl. their open state |
| [getChartRef(chartId)](https://www.adaptabletools.com/docs/reference/chartingapi.md#getchartref) | `ChartRef \| undefined` | Retrieves AG Grid ChartRef for given ChartId |
| [getCurrentChartModels()](https://www.adaptabletools.com/docs/reference/chartingapi.md#getcurrentchartmodels) | `ChartModel[]` | Retrieves current user-generated Charts |
| [getExternalChartDefinitionByName(name)](https://www.adaptabletools.com/docs/reference/chartingapi.md#getexternalchartdefinitionbyname) | `ExternalChartDefinition \| undefined` | Retrieves Chart definition by name |
| [getExternalChartDefinitions()](https://www.adaptabletools.com/docs/reference/chartingapi.md#getexternalchartdefinitions) | `ExternalChartDefinition[]` | Retrieves all adaptable external Chart definitions |
| [getOpenChartContainer(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#getopenchartcontainer) | [`ChartContainer`](https://www.adaptabletools.com/docs/reference/chartcontainer.md)` \| null` | Retrieve name of container in which Chart is open; returns null if Chart is not open |
| [getPersistedCharts()](https://www.adaptabletools.com/docs/reference/chartingapi.md#getpersistedcharts) | `ChartModel[]` | Retrieves persisted Charts from Adaptable State |
| [isChartingEnabled()](https://www.adaptabletools.com/docs/reference/chartingapi.md#ischartingenabled) | `boolean` | Whether AdapTable's Charting functionality is available |
| [saveCurrentCharts()](https://www.adaptabletools.com/docs/reference/chartingapi.md#savecurrentcharts) | `void` | Saves all current Charts into Adaptable State |
| [setChartEditable(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#setcharteditable) | `void` | Make a Chart Editable (i.e. not Read-Only) |
| [setChartReadOnly(chartDefinition)](https://www.adaptabletools.com/docs/reference/chartingapi.md#setchartreadonly) | `void` | Make a Chart Read-Only |
| [showChartDefinition(chartDefinition, container)](https://www.adaptabletools.com/docs/reference/chartingapi.md#showchartdefinition) | `ChartRef` | Opens a Chart Definition |
| [showChartDefinitionOnce(chartDefinition, container)](https://www.adaptabletools.com/docs/reference/chartingapi.md#showchartdefinitiononce) | `ChartRef \| undefined` | Displays a Chart; if Chart is already open, 2nd Chart is not opened |
| [showPersistedCharts()](https://www.adaptabletools.com/docs/reference/chartingapi.md#showpersistedcharts) | `ChartRef[]` | Displays all persisted Charts |
---
# Using Charts
Canonical page: https://www.adaptabletools.com/docs/handbook-charts-using
- Run-time users can save and re-open AG Grid charts they have created
- If Charting locations have been provided, they can choose where to display these charts
Run-time users of AdapTable can manage the charts which they create using AG Grid.
## Saving Charts
AdapTable users can name and save charts into [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md).
This requires the `saveChartBehaviour` property in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) to be set to `manual`
A Notification will appear prompting the user to provide a name for the Chart, whereupon the Chart is saved.
## Opening Charts
Any AG Grid charts which have been named and saved will appear in a dropdown in:
- the Charting [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) in the [Dashboard](https://www.adaptabletools.com/docs/ui-dashboard/index.md)
- the Charting [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md)
- the Charting [Status Bar Panel](https://www.adaptabletools.com/docs/ui-status-bar/index.md)
Selecting a chart in any of these and clicking 'Open' will display the Chart.
- If specified Chart locations have been provided in [Charting Options](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md), users can select where to display the Chart
- See [Configuring Charts](https://www.adaptabletools.com/docs/handbook-charts-configuring/index.md) for more details on how to provide Chart locations
### Opening Saved Charts
By default, AdapTable does not store details of which Charts are currently opened in which Containers.
However this is straightforward to do by leveraging the [Application section of Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-custom/index.md).
This can then be used to automatically re-open any Charts when the Application restarts
**Example: Displaying Saved Charts**
Displayed visible Charts when AdapTable restarts
- This example uses Application State to store details of which Charts were displayed
- Charts have been placed in 2 Layouts
- Switch between the 2 Layouts to see the Charts display in different Containers
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Charts in App state',
chartingOptions: {
saveChartBehaviour: 'manual',
chartContainers: [
{
name: 'Top Container',
chartsDisplay: 'multiple',
element: '#demoOutputAbove',
},
{
name: 'Bottom Container',
element: '#demoOutputBelow',
},
],
},
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Charting',
Toolbars: ['Layout', 'Charting'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Uuid: '22897acb-3ad1-4011-9fd0-0bf9f43d474e',
Name: 'Standard Layout',
TableColumns: [
'github_stars',
'github_watchers',
'name',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
AutoSizeColumns: true,
OpenCharts: [
{ChartName: 'bar', ContainerName: 'Top Container'},
{ChartName: 'pie', ContainerName: 'Top Container'},
],
},
{
Uuid: '04dff093-5388-4e9a-a320-6fd178e86260',
Name: 'Demo Layout 2',
TableColumns: [
'github_stars',
'github_watchers',
'name',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
AutoSizeColumns: true,
OpenCharts: [
{ChartName: 'pie', ContainerName: 'Bottom Container'},
],
},
],
},
// CHARTING STATE
Charting: {
ChartDefinitions: [
{
Uuid: '8d2aff65-f44f-4363-b90b-51bd684399b4',
Name: 'bar',
Model: {
modelType: 'range',
chartId: 'frameworks-bar',
chartType: 'groupedBar',
chartThemeName: 'ag-vivid-dark',
chartOptions: {},
cellRange: {
rowStartIndex: 4,
rowEndIndex: 11,
columns: ['name', 'github_watchers'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
{
Uuid: 'e6f19fdc-fdc2-4554-b7ae-47443bdbbad7',
Name: 'pie',
Model: {
modelType: 'range',
chartId: 'frameworks-pie',
chartType: 'pie',
chartThemeName: 'ag-vivid-dark',
chartOptions: {},
cellRange: {
rowStartIndex: 3,
rowEndIndex: 9,
columns: ['name', 'github_watchers'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
// enable charts and set a theme
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
// Charts linked to each layout open automatically via `OpenCharts` on the layout definition.
export const onAdaptableReady = (_info: AdaptableReadyInfo) => {};
```
```css
#demoOutputAbove,
#demoOutputBelow {
display: flex;
max-height: 500px;
}
```
## Closing Charts
Any open chart can be closed from the same lcoations which which can open it.
## Editing Charts
Charts can be edited by clicking the _Edit_ button for that Chart in the [Charts Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md).
This will open the [Wizard](https://www.adaptabletools.com/docs/ui-settings-panel-wizards/index.md) for that Chart allowing it be edited as requied.
## Deleting Charts
Charts can be deleted by clicking the _Delete_ button for that Chart in the [Charts Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md).
### ReadOnly Charts
Individual Charts can be set to be `ReadOnly` if required.
This will override the [Module Entitlements](https://www.adaptabletools.com/docs/handbook-permissioning-modules/index.md) for Charting
Read-Only Charts can be displayed and closed but they cannot be deleted.
There are 2 ways to set a Chart to Read-Only:
- Setting `IsReadOnly` to _true_ if providing the full Chart definition in [Charting Initial State](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md) (a very rare use case)
- Calling the `setChartReadOnly` function in [Charting API](https://www.adaptabletools.com/docs/handbook-charts-technical-reference/index.md)
- You will likely need to add a Custom button somewhere to do this
**Example: Read-Only Charts**
Settings Charts to be Read-Only
- This example contains 2 Charts:
- Bar Chart - which has a `Full` Entitlement and can be displayed, edited and deleted
- Pie Chart - which has a `ReadOnly` Entitlement and can be displayed but not edited or deleted
- Switch between the 2 Charts and note how the Edit and Delete buttons in the Toolbar are alternately enabled / disabled
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Read only Charts',
initialState: {
Dashboard: {
Tabs: [
{
Name: 'Charting',
Toolbars: ['Charting'],
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Charting'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Uuid: '22897acb-3ad1-4011-9fd0-0bf9f43d474e',
Name: 'Standard Layout',
TableColumns: [
'github_stars',
'github_watchers',
'name',
'language',
'license',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
AutoSizeColumns: true,
},
],
},
Charting: {
ChartDefinitions: [
{
Uuid: '8d2aff65-f44f-4363-b90b-51bd684399b4',
Name: 'Bar Chart',
Model: {
modelType: 'range',
chartId: 'framework-bar',
chartType: 'groupedBar',
chartThemeName: 'ag-vivid-dark',
chartOptions: {},
cellRange: {
rowStartIndex: 4,
rowEndIndex: 11,
columns: ['name', 'github_watchers'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
{
Uuid: 'e6f19fdc-fdc2-4554-b7ae-47443bdbbad7',
Name: 'Pie Chart',
IsReadOnly: true,
Model: {
modelType: 'range',
chartId: 'framework-pie',
chartType: 'pie',
chartThemeName: 'ag-vivid-dark',
chartOptions: {},
cellRange: {
rowStartIndex: 3,
rowEndIndex: 9,
columns: ['name', 'github_watchers'],
},
suppressChartRanges: false,
unlinkChart: false,
},
},
],
},
},
};
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {rowData} from 'rowData';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
rowData: rowData,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
// enable charts and set a theme
enableCharts: true,
chartThemes: ['ag-vivid', 'ag-vivid-dark'],
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
---
# Column Filters
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter
- AdapTable offers very rich, powerful **column filtering** capability
- Each Column Filter can contain multiple conditions (using Predicates) together with AND / OR functionality
- These can either by System Predicates (provided by AdapTable) or Custom Predicates (defined by users)
- Column Filters complement (and can be used together with) the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md)
- There are 2 Custom Filter Components provided:
- Filter Bar - between Column Header and first row of Grid
- Filter Form - available from Column Menu, Filter Tool Panel and other places
Column Filtering in AdapTable is extremely intuitive, rich and extensible.
Column Filters complement, and work in conjunction, with the [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md); both can be active at the same time
Users can create as many Column Filters as required and AdapTable will automatically update AG Grid so that only rows which match **all** Column Filters will be displayed
Filtering is a constant operation - Column Filters will be continually re-applied as data in the grid changes
## Filter Components
AdapTable offers 2 [Filter Components](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) to enable users to perform run-time Column Filtering:
- **Filter Form**, a rich, [configurable](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) component that provides full filtering capability
- **Filter Bar** (underneath Column Header), designed to facilitate instant filtering (including wildcards)
Both components offer full, advanced, filtering capability including:
- displaying all available Column Filter Predicates (for that Column) and any inputs required
- support for Custom Predicates
- a dedicated UI for `In` (and `NotIn`) Predicate enabling [multiple values to be displayed and selected](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md)
- automatically updating the [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) (and [Layout State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md)) as Column Filters are applied
- The Filter Form and Filter Bar **replace** AG Grid's Filter Form and Floating Filter respectively
- They are the **only** instances where AdapTable provides alternative, not complementary, functionality to AG Grid
### Other Filter Components
In addition to the 2 Filter Components, run-time users can create and edit Column Filters in the [Layout Wizard](https://www.adaptabletools.com/docs/ui-settings-panel-wizards/index.md).
AdapTable also provides 4 other filter-related components.
These allow Users to *clear* or *suspend* some or all current Column Filters and are available as:
- [Dashboard Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars)
- [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md)
- [Status Bar Panel](https://www.adaptabletools.com/docs/ui-status-bar/index.md)
- [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md)
## Predicates
Column Filters are essentially a simple combination of 2 objects:
- an [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) - **where** the Column Filter is applied
- a [Predicate](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) (a boolean function dynamically evaluated by AdapTableQL) - **what** is applied
- AdapTable offers many [System Predicates](https://www.adaptabletools.com/docs/handbook-column-filter-system-filters/index.md) available for Filtering for each Column DataType
- See the [Adaptable QL Predicate Guide](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) for full details about Predictates which are widely-used across AdapTable
**Example: Filters**
Basic Filtering using System Predicates
- This example shows 5 Column Filters applied across 2 Layouts:
- The `Filtered` Layout contains 3 Filters:
- `Language` is 'Typescript' or 'JavaScript' using `In` Predicate (similar to SQL)
- `Name` ends with '.js. - using `EndsWith` Predicate
- `Published` since 2016 - using `After` Predicate
- The `MIT` Layout contains 2 Filters:
- `License` equals 'MIT Licence' - using `Is` Predicate
- `Github Stars` between 20k and 90k - using `Between` Predicate
- We have also chosen to display the Column Filter [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars) in the Dashboard, and set the Clear and Suspend Buttons to be displayed
- Switch between Layouts and see that the different Layout display different Filters
- Change the Column Filter for the `Langauage` Column to include 'Javascript' and 'HTML' projects
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Basic Filtering',
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
PinnedToolbars: ['Layout', 'ColumnFilter'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Filtered',
Layouts: [
{
Name: 'Filtered',
TableColumns: [
'name',
'language',
'github_stars',
'license',
'pushed_at',
],
ColumnFilters: [
{
ColumnId: 'language',
Predicates: [
{
PredicateId: 'In',
Inputs: ['TypeScript', 'JavaScript'],
},
],
},
{
ColumnId: 'name',
Predicates: [
{
PredicateId: 'EndsWith',
Inputs: ['.js'],
},
],
},
{
ColumnId: 'pushed_at',
Predicates: [
{
PredicateId: 'After',
Inputs: ['2016-01-01'],
},
],
},
],
},
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'pushed_at',
],
ColumnFilters: [
{
ColumnId: 'license',
Predicates: [
{
PredicateId: 'Is',
Inputs: ['MIT License'],
},
],
},
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'Between',
Inputs: ['20000', '90000'],
},
],
},
],
Name: 'MIT',
},
],
},
},
};
```
### Custom Predicates
As the demo above illustrates, most Column Filters use [System Filter Predicates](https://www.adaptabletools.com/docs/handbook-column-filter-system-filters/index.md).
However Column Filters can also leverage bespoke, user-defined [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md).
- The [Guide to using Custom Filters](https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters/index.md) explains more and contains demos
- See [Custom Predicate Definitions](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) for in-depth instructions
### Multiple Predicates
A Column Filter can contain **multiple Predicates** if required.
Multiple Predicates are also available in [Alerts](https://www.adaptabletools.com/docs/handbook-alerting/index.md), [Conditional Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) and [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md),
By default the Predicates are joined using `AND` logic, meaning **all** Predicates need to be true for a row to pass.
However the [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md) object includes a [`PredicatesOperator`](https://www.adaptabletools.com/docs/reference/predicatesoperator.md) property allowing for `OR` to be used instead.
When `OR` is used the row is displayed if **any** of the Conditions in the Column Filter return true
Multiple Predicates can only be created in the Filter Form (and not the Filter Bar)
**Example: Multiple Predicate Filters**
Filtering using Multiple Predicates
- This example shows 2 Column Filters each using Multiple Predicates (but with a different operator):
- `Name` - `Contains` 'e' **AND** `EndsWith` 's' (we explicitly added the `AND` operator but its not strictly required as its the default)
- `Github Stars` - `LessThan` 10000 **OR** `GreaterThan` 20000
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Multiple Predicate Filtering',
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
PinnedToolbars: ['Layout', 'ColumnFilter'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Filtered',
Layouts: [
{
Name: 'Filtered',
TableColumns: [
'name',
'language',
'github_stars',
'license',
'pushed_at',
],
ColumnFilters: [
{
ColumnId: 'name',
Predicates: [
{
PredicateId: 'Contains',
Inputs: ['e'],
},
{
PredicateId: 'EndsWith',
Inputs: ['s'],
},
],
// Not required as this is default value
PredicatesOperator: 'AND',
},
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'LessThan',
Inputs: ['10000'],
},
{
PredicateId: 'GreaterThan',
Inputs: ['20000'],
},
],
PredicatesOperator: 'OR',
},
],
},
],
},
},
};
```
### Formatted Cells
AdapTableQL evaluates the Predicate based on the underlying value in the Cell.
AdapTable will evaluate Filters using the **raw** value of the cell (rather than the display value)
This means that if a column uses an AG Grid [Cell Component](https://www.ag-grid.com/javascript-data-grid/cell-rendering/) (previously called a Cell Renderer), an AG Grid [Value Formattter](https://www.ag-grid.com/javascript-data-grid/value-formatters/) or an Adaptable [Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md), the filter is evaluated using the cell's underlying (i.e. raw) value, and not what is actually displayed in the Grid.
- One exception to this rule is the `In` Predicate which shows the cell's display value
- But only if an AG Grid [Value Formattter](https://www.ag-grid.com/javascript-data-grid/value-formatters/) or Adaptable [Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md#display-formats) are used (and not an [AG Grid Cell Component](https://www.ag-grid.com/javascript-data-grid/cell-rendering/))
## Using Column Filters
Run-time users are able to create and edit Column Filters using all the available Filter Components.
- Unlike other Modules, Column Filters cannot be created in the Module's [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) via a wizard
- Filters can **only** be created using the UI Filter components or in the Layout Editor's Column Filter section
In addition, users can leverage the Column Filter [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars), [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md), [Status Bar Panel](https://www.adaptabletools.com/docs/ui-status-bar/index.md) and [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) to clear, suspend or share some or all current Filters.
Column Filters are persisted in the Layout section of the Adaptable State and then automatically re-applied on application re-start when the relevant Layout is loaded.
### Creating Filter via Context Menu
The [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) has a "Filter on Cell Value(s)" option (available only if the selected cells are in one Column).
This will create a new `Equals` Filter based on the value of what is the currently selected cell.
If there is more than one distinct cell value in the Column's selection range, an `IN` filter is created instead
### Seeing Current Filters
AdapTable shows users the currently applied Column Filters in AG Grid in the Filter [Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars), [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md), [Status Bar](https://www.adaptabletools.com/docs/ui-status-bar/index.md) and [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) .
Each provides a description of the Predicate and Column together with a _Clear_ button
- AG Grid indicates which Columns are filtered in the Column header and Filter Tool Panel (in Sidebar)
- AdapTable changes the style of the Column Header for any currently filtered columns
### Suspending Filters
Column Filters - like all AdapTable Objects - can be [suspended](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-initial-state/index.md#adaptable-objects#suspending-objects). When a Column Filter is suspended, the Filter Bar and Filter Form show details of, but do not run, the associated Predicate.
You need either to un-Suspend or Clear a suspended Filter before setting a new Filter for that Column
## Filtering Dynamic Columns
In [AdapTable Version 21.1](https://www.adaptabletools.com/support/version-211-release-note), Column Filtering was extended to Columns created dynamically by AG Grid.
These dynamically generated Columns can all be filtered (click the links to see demos):
- [Row Grouped Columns](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md#filtering) (a filter icon in Row Grouped column opens the [Filter Form](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) when clicked)
- [Pivot Result Columns](https://www.adaptabletools.com/docs/handbook-layouts-pivot-filtering/index.md)
- [Tree Grid Key Columns](https://www.adaptabletools.com/docs/handbook-tree-data-grid/index.md#filtering) (but using AG Grid filters)
## Configuring Filters
Developers are able to configure Filters at design time as follows:
- Use [Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md) to **define** Column Filters
- Use [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) section of Adaptable Options to **configure** Filters behaviour and display
See [Defining Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter-defining/index.md) and [Configuring Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter-configuring/index.md) for more details
---
# Filter Components
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-components
- AdapTable provides 2 main components to allow run-time users to create Column Filters with multiple conditions
- Filter Form - a popup that contains all the functionality required to manage complex filtering
- Filter Bar - sits between the Column Header and the first row of the Grid - and designed for quick filtering
- Both components enable the IN filter to be used to select multiple column values
Column Filtering in AdapTable is done via 2 main UI components:
- Filter Form - popup offering comprehensive, multi-Predicate filtering functionality (also used in ToolPanel)
- Filter Bar - bar underneath the Column Header, designed for quick filtering
## Filter Form
The Adaptable Filter Form provides a way to create powerful Filters with just a few clicks.
Every column in AdapTable will display a bespoke Filter Form.
The Filter Form contains:
- list of available Predicates for the Column (based on its data type)
- list of distinct column values (when using the [In Predicate](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md))
- `Add Condition` button to add additional predicates to the Column Filter
- `Clear Filters` button
- `Apply Filter` button (if [Manually Applying Filters](https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying/index.md) is turned on)
The Filter Form is only displayed for Columns with `filterable` set to _true_ in AG Grid GridOptions
### Filter Form Locations
The AdapTable Filter Form is displayed in 2 places in the Grid:
- As a popup that opens when clicking the Filter button in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md)
- In the _Filters_ Tool Panel in the [AG Grid sidebar](https://www.ag-grid.com/javascript-data-grid/side-bar/) (generally displayed to the right of the grid)
## Filter Bar
The Filter Bar is a custom AdapTable UI Component that replaces AG Grid's Floating Filter.
It is displayed between the Column Header and the first data row in AG Grid.
### Setting up and Displaying the Filter Bar
Set `floatingFilter` to *true* in `GridOptions` for all Columns which should display a Filter Bar.
Either set each column individually:
```ts {6}
export const columnSchema: ColDef[] = [
{
field: 'make',
headerName: 'Make',
cellDataType: 'text',
floatingFilter: true,
}
];
```
or use the `defaultColDef`:
```ts {4}
const gridOptions: GridOptions = {
defaultColDef: {
filter: true,
floatingFilter: true,
},
}
```
The Filter Bar is only available if at least **one** column in Grid Options sets this property to *true*
The Filter Bar comprises 2 elements:
- **Predicate Dropdown** - sits on the left hand side of the Filter Bar and contains all the System and Custom Filters which have [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for that column
- **Input Control** - if the selected Predicate requires `inputs`, a control appears enabling these to be entered
- The type of the input control varies depending on the **Data Type** of the [Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md)
- A TextBox is used for strings, a Date Picker for dates, and a Numeric Editor for numbers
- If the selected Predicate requires no inputs (e.g. `Today`), its name is displayed here instead
- If the selected Predicate requires 2 values (e.g. `Between`) then 2 inputs are displayed
### `IN` Predicate
The `IN` predicate differs to other predicates as it can receive multiple column values.
When this predicate is selected, AdapTable changes the input box to 'Select Values', and AdapTable lists the distinct values for the column with a checkbox by each.
Users are then able to provide the inputs to the `IN` Predicate by selecting the checkboxes they require.
See the Guide to the [In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md) for more information, including how to display custom values
### Wildcards
Wildcards are available in the Filter Bar to speed up filtering, and reduce mouse usage.
For example, you can type '>' in a numeric input to jump to the `GreaterThan` Predicate.
The 6 wildcards provided by AdapTable are:
| Wildcard | Predicate | Available Columns |
| -------- | ------------- | ----------------- |
| `` = `` | `Equals` | Text, Number |
| `` > `` | `GreaterThan` | Number |
| `` < `` | `LessThan` | Number |
| `` : `` | `Between` | Number |
| `` [ `` | `In` | All Columns |
| `` # `` | `In` | All Columns |
### `quickFilterWildcards`
Shortcut Keys to activate a Filter Bar Predicate
Use this property to add or remove the wildcards used in the Filter Bar.
Provide New Wildcards
Users can set new wildcards by supplying the `PredicateId` and the wildcard keys (in the form of an array) to trigger it
```ts {6}
// Set a new wildcard of exclamation for the NotBetween Predicate
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions: {
quickFilterWildcards:{
NotBetween: ['!'],
}
}
}
};
```
Update Wildcards
Users can update wildcards by supplying the `PredicateId` and the wildcard keys (in the form of an array) that should replace the existing implementation
- This is useful if you explicitly want to filter on a cell value, or use in a different way, a wildcard value
- e.g. the '[' wildcard (used for `In` predicate) is a legitimate character when using the `Regex` Predicate
```ts {6}
// Keep the '#' wildcard for In Predicate (but remove '[' so we can use in RegEx)
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions: {
quickFilterWildcards:{
In: ['#'],
}
}
}
};
```
Clear Existing Wildcards
To remove a wildcard shipped by AdapTable simply provide an empty array for that `PredicateId`.
```ts {6}
// Clear the Wildcards for the In Predicate
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions: {
quickFilterWildcards:{
In: [],
}
}
}
};
```
**Example: Filter Bar Wildcards**
Adding and removing Wildcards in Filter Bar
- This Demo shows how to manage Wildcards in the Filter Bar:
- an empty array has been provided for `In` - so that neither of the System wildcards for that Predicate are operable
- a value of '!' has been provided for the NotEquals Predicate - so that entering that in a number column will change the Predicate automatically
- Type '[' or '#' in the `Language` column and see that the `In` predicate does not appear
- Type '!' in `Github Stars` column and note that the Predicate changes to `NotEquals`
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Filter ּBar Wildcards',
filterOptions: {
columnFilterOptions: {
// Remove the System Wildcards for the In Predicate
// Add a '!' for the Not Equals Predicate
quickFilterWildcards: {
NotEquals: ['!'],
In: [],
},
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
PinnedToolbars: ['ColumnFilter'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Hiding the Filter Bar
The Filter Bar can be hidden or made visible, both at design time and run time.
- **Design-time** visibility is provided via the `showQuickFilter` property in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md)
### `showQuickFilter`
Whether to display Filter Bar between Column Header and the Grid (provided its been setup)
AdapTable, by default, will display the Filter Bar - provided that one has been set up.
Set this property to *false* if you want a Filter Bar available to your users - but hidden by default.
Hidden Filter Bars can be made visible by selecting `Show Filter Bar` in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md)
```ts {4}
// Hide the Filter Bar (but allow it to be made visible by users)
const adaptableOptions: AdaptableOptions = {
columnFilterOptions: {
showQuickFilter: false
}
};
```
- **Run-time** Filter Bar visbility can be handled in various ways including:
- Checking / unchecking the `Quick Filter Checkbox` in the [Filter Toolbar](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md)
- Checking / unchecking the `Quick Filter Checkbox` in the [Filter Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md)
- Accessing the `Show / Hide Quick Filter Bar` [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) Item
- Filter Bar Visibiilty which is changed mid-session is **not** subsequently persisted, as it is not part of [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md)
- However, you can easily save and restore Filter Bar visbility by using the [Application](https://www.adaptabletools.com/docs/dev-guide-adaptable-state-custom/index.md) section of [Adaptable State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md)
#### Hiding Filter Bar Elements
As well as hiding the Filter Bar entirely, the dropdown on the left of each Column's Floating Bar can also be hidden.
- This is often the case for Boolean columns or when screen real estate is very tight
- This can be hidden on a column by column basis if required
This is achieved using the `hideQuickFilterDropdown` function in the `columnFilterOptions` section of Filter Options.
### `hideQuickFilterDropdown`
Don't show the Filter Bar Dropdown for some Columns
For those columns where the Predicates dropdown might not be required in the Filter Bar, the `hideQuickFilterDropdown` function can be used.
The [`ColumnFilterContext`](https://www.adaptabletools.com/docs/reference/columnfiltercontext) object contains a single property containing the [Adaptable Column](https://www.adaptabletools.com/docs/dev-guide-columns-adaptable-column/index.md) being filtered.
```ts {4,5,6}
// Dont show the Dropdown in Filter Bar for Boolean columns
const adaptableOptions: AdaptableOptions = {
columnFilterOptions: {
hideQuickFilterDropdown: (filterContext: ColumnFilterContext) => {
return filterContext.column.dataType == 'boolean';
}
}
};
```
### Filter Bar Debounce
By default AdapTable will apply Filters every 250ms in response to user entry in the Filter Bar.
Where this is too quick, e.g. if running Filters on the Server and less frequent Filtering is required, the `quickFilterDebounce` property in Filter Options can be used.
This differs from AdapTable's automatic post-edit filter pass described in [Filtering when Data Changes](https://www.adaptabletools.com/docs/handbook-column-filter-configuring/index.md)
### `quickFilterDebounce`
Time to wait before applying the Filter after entering a value
By default AdapTable will wait 250ms (1/4 of a second) before applying the Filter after a user enters text in the Filter Bar.
This ensures speedy filtering while allowing users to type quickly.
Use this property to set a different throttle value if required:
```ts {4}
// Wait a second before Filtering the grid after the user updates the Filter Bar
const adaptableOptions: AdaptableOptions = {
columnFilterOptions: {
quickFilterDebounce: 1000,
}
};
```
**Example: Filter Bar Configuration**
Configuring Filters using Filter Options
- This Demo illustrates a [Column Filter Option](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) for configuring the Filter Bar:
- an implementation provided for `hideQuickFilterDropdown` property so that the dropdown does not appear in Boolean columns
```ts
import {
AdaptableOptions,
AdaptableColumnContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Filter ּBar Options',
filterOptions: {
columnFilterOptions: {
hideQuickFilterDropdown: (context: AdaptableColumnContext) => {
return context.column.dataType == 'boolean';
},
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
PinnedToolbars: ['ColumnFilter'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'description',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Filter Bar Height
AdapTable will set the height of the Filter Bar to the AG Grid default.
If that is not required, the height can be set using the `quickFilterHeight` property in Filter Options:
### `quickFilterHeight`
Sets height of Filter Bar (if not provided AG Grid default is used)
By default AdapTable will allow AG Grid to set the height of the Filter Bar (by setting its Floating Filter).
Use this property to set the height explicitly:
```ts {4}
// Explicitly set the height of the Filter Bar
const adaptableOptions: AdaptableOptions = {
columnFilterOptions: {
quickFilterHeight: 80,
}
};
```
## Other Filter Components
In addition to the 2 main Filter Components, AdapTable provides 4 additional filter-related components:
- [Dashboard Toolbar](https://www.adaptabletools.com/docs/ui-dashboard/index.md#tabs-and-toolbars)
- [Tool Panel](https://www.adaptabletools.com/docs/ui-tool-panel/index.md)
- [Status Bar Panel](https://www.adaptabletools.com/docs/ui-status-bar/index.md)
- [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md)
Each of these components allow run-time Users to:
- see which Column Filters are active
- clear Column Filters
- Suspend / Reactivate Columns
- Open the Filter Form (to edit Column Filters)
---
# Configuring Column Filters
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-configuring
- Column Filtering in AdapTable includes advanced features for more demanding use cases
- These are primarily available in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) and allow developers to configure Filtering as needed
AdapTable provides many configuration options which allow developers to set up Column Filtering to meet precise requirements.
Most of these are available in the [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) section of Adaptable Options.
- This page lists some general Column Filtering options
- See [Filter Components](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) and [In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md) for options to configure those UI Filter Components
## Using AG Grid Filtering
By default AdapTable provides its own Filter controls instead of those provided by AG Grid.
This is the only place in AdapTable where it provides alternative, rather than complementary, functionality
We do this because we think that AdapTable offers a richer, more intuitive and more configurable set of Filters.
AdapTable provides Filters in Layouts meaning you can save,and easily switch between, different Filter sets.
- An additional benefit is that AdapTable allows users to access Grid Filter and Column Filters simultaneously
- This is not possible using the AG Grid equivalents, where you need to choose between them
In the rare use case where AG Grid's filters are preferred, they can easily be turned on by setting `useAdaptableFiltering` to false in Filter Options.
- This does not remove AdapTable Filtering logic, e.g the API functions will all stil operate
- However it does hide all AdapTable Filtering UI controls so they cannot be accessed accidentally
### `useAdaptableFiltering`
Turns of AdapTable Filtering and uses AG Grid Filters
Use this property to specify usage of AG Grid's Filters (in preference to those provided by AdapTable).
```ts {4}
// Use AG Grid Filters and hide AdapTable's filters
const adaptableOptions: AdaptableOptions = {
filterOptions - {}
useAdaptableFiltering: false
}
};
```
**Example: Using AG Grid Filtering**
Selecting AG Grid Filters instead of AdapTable
- In this example we have turned off AdapTable Filtering (and use AG Grid's instead)
- As a reuslt we see AG Grid filters in the Filter Bar, Filter Form and Filter ToolPanel
- Additionally Column Filters and Grid Filter are absent from the Layout and all Adaptable Filtering controls (toolpanels, toolbars etc) are missing
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'AG Grid Filtering Demo',
filterOptions: {
useAdaptableFiltering: false,
},
initialState: {
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Non Filterable Rows
By default all data rows in AdapTable will be evaluated in Column Filtering.
Occasionally, the use case arises where some rows should **always** be present and never subject to filtering.
This can be configured using the `isRowFilterable` property in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md).
### `isRowFilterable`
Configures which Data Rows cannot be filtered
By default AdapTableQL will evaluate every row in the Grid when it applies a Column Filter.
Use this property to specify which rows should never be filtered.
```ts
isRowFilterable?: (context: IsRowFilterableContext) => boolean;
```
The property takes the form of a function that receives an `IsRowFilterableContext` object and returns a boolean.
The [`IsRowFilterableContext`](https://www.adaptabletools.com/docs/reference/isrowfilterablecontext.md) is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [data](https://www.adaptabletools.com/docs/reference/isrowfilterablecontext.md#data) | `TData` | The data in the Row Node |
| [rowNode](https://www.adaptabletools.com/docs/reference/isrowfilterablecontext.md#rownode) | `IRowNode` | The Row Node about to be evaluated |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/isrowfilterablecontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
```ts {4}
// Don't filter on the first row in each Row Group and any row where the Language is TypeScript
const adaptableOptions: AdaptableOptions = {
filterOptions - {}
columnFilterOptions = {
isRowFilterable: (context: IsRowFilterableContext) => {
return context.rowNode.firstChild || context.data['language'] === 'TypeScript';
},
}
};
```
**Example: Non-Filterable Rows**
Configuring which rows cannot be filtered
- In this example we provide an implementation for `isRowFilterable` property, so these rows are **never** filtered:
- the first row in the Grid
- any row where `Language` is 'HTML'
- We filter the `Language` column on 'TypeScript' but still see "JavaScript" for the `Language` column in first row, and see 'HTML' as those rows are excluded from filtering
```ts
import {
AdaptableOptions,
IsRowFilterableContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Non Filterable Rows',
filterOptions: {
isRowFilterable: (context: IsRowFilterableContext) => {
return !context.rowNode.firstChild && context.data['language'] !== 'HTML';
},
},
initialState: {
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Filtered Layout',
Layouts: [
{
Name: 'Filtered Layout',
TableColumns: [
'name',
'language',
'github_watchers',
'github_stars',
'has_wiki',
'open_issues_count',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
'updated_at',
'pushed_at',
'description',
],
ColumnFilters: [
{
ColumnId: 'language',
Predicates: [
{
PredicateId: 'Is',
Inputs: ['Typescript'],
},
],
},
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Filtering on Special Columns
By default, AdapTable allows all [Calculated Columns](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [FreeText Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) to be filterable.
This behaviour can be changed via the `enableFilterOnSpecialColumns` property in [Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md).
### `enableFilterOnSpecialColumns`
Allows filtering on Calculated and FreeText columns
Setting this property to _false_ will disallow filtering on **all** Calculated and Free Text Columns.
This will **override** the `Filterable` property value in the Calculated Column or Free Text Column definition
```ts {4}
// Don't allow Calculated or Free Text Columns to be filterable
const adaptableOptions: AdaptableOptions = {
filterOptions: {
enableFilterOnSpecialColumns: false,
},
};
```
If this property is `true`, you can still set filtering to `false` on a per Calculated / Free Text Column basis
```ts {4,16}
// Allow Calculated & Free Text Columns to be filterable
const adaptableOptions: AdaptableOptions = {
filterOptions:{
enableFilterOnSpecialColumns: false
}
};
// But override at Calculated Column level
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'total_pr_count',
Query: { ScalarExpression: '[open_pr_count] + [closed_pr_count]' },
CalculatedColumnSettings: {
DataType: 'number',
Filterable: false,
},
}],
},
```
## Clearing Column Filters on Startup
AdapTable always saves previously applied Column Filters (and the Grid Filter) into AdapTable State (via the Current Layout).
It will then automatically re-apply these Filters when the Application is reloaded.
If this behaviour is not desired, set the `clearFiltersOnStartUp` property in [Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) to _true_.
### `clearFiltersOnStartUp`
Clear any Column or Grid Filters applied in previous session when Application re-starts
AdapTable saves all [User State](https://www.adaptabletools.com/docs/dev-guide-adaptable-state/index.md) to either local or remote storage, including Column Filters.
It then re-applies any persisted Columns Filters when the application re-starts.
Setting this property to _true_ will remove any Column Filters in Adaptable State from the previous session, and display a non-filtered AG Grid instance.
```ts {4}
// Clear any previously set Column or Grid Filters when AdapTable re-starts
const adaptableOptions: AdaptableOptions = {
filterOptions = {
clearFiltersOnStartUp: true,
},
};
```
The `clearQuickSearchOnStartUp` property in [Quick Search Options](https://www.adaptabletools.com/docs/handbook-quick-search-technical-reference/index.md) will clear a saved [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md)
## Indicating Filtered Columns
AdapTable distinctively renders the Column Header for any currently filtered columns.
This is particularly helpful when users restart the application, unaware that filters were persisted
If this is not desired behaviour, set the `indicateFilteredColumns` property to _false_.
- AG Grid will still indicate filtered Columns by providing a different filter icon in the Column Header
- You will need to change the AG Grid css to handle this
### `indicateFilteredColumns`
Style Column Header to visually identify which Columns are currently filtered
Stops AdapTable from making the Header for currently filtered columns distinctive.
```ts {5}
// Don't distinctively show Filtered Columns
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions: {
indicateFilteredColumns: false,
},
},
};
```
## Column Filter Applied Event
AdapTable will fire the [Column Filter Applied Event](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) whenever a Column Filter changes.
This allows you to listen to Column Filters which have changed in AdapTable and react accordingly.
This is often used when wanting to [evaluate expressions on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md)
**Example: Column Filter Applied Event**
Listening to Column Filter Applied Event
- In this example we listen to the [Column Filter Applied Event](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) and output the Event's info to the console
- Create a Column Filter and inspect the Console to see the output from the Event
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Column Filter Applied Event',
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
PinnedToolbars: ['ColumnFilter'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
import {
AdaptableReadyInfo,
ColumnFilterAppliedInfo,
} from '@adaptabletools/adaptable';
export const onAdaptableReady = ({adaptableApi}: AdaptableReadyInfo) => {
adaptableApi.eventApi.on(
'ColumnFilterApplied',
(columnFilterAppliedInfo: ColumnFilterAppliedInfo) => {
console.log('Column Filter Applied', columnFilterAppliedInfo);
}
);
};
```
---
# Custom Column Filters
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters
- Column Filters can use bespoke Custom Predicates in addition to the System Predicates that AdapTable provides
Most Column Filters use [System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md#system-and-custom-predicates) which are shipped with AdapTable.
However Column Filters can also leverage bespoke, user-defined [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md).
- See [Custom Predicate Definitions](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) to learn how Developers can provide design-time Custom Predicates
- Once defined, these will be displayed in in the Filter Components and available to be used in Filters
**Example: Custom Filters**
Filtering using user-defined Custom Predicates
- This example shows a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) with 3 Column Filters each using a [Custom Predicate](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md):
- `Github Stars` uses the `Popular` Predicate - which only shows values with more than 10,000 stars
- `Language` uses the `Scripting` Predicate - which limits values to 'JavaScript' or 'TypeScript' (we also created a [Conditional Style](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) using this Predicate)
- `Created` has the `Last Ten Years` Predicate applied - which filters to dates in previous 10 - and has a [Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) of all `Date` columns
- Clear the `Scripting` Filter in the `Language` column and note how the cells with 'HTML' are not formatted (since they do not pass the Predicate which is still being used for Formatting)
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Filter Predicates',
predicateOptions: {
customPredicateDefs: [
{
id: 'popular',
label: 'Popular',
columnScope: {
ColumnIds: ['github_stars'],
},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
return params.value > 10000;
},
},
{
id: 'scripting',
label: 'Scripting',
columnScope: {
ColumnIds: ['language'],
},
moduleScope: ['columnFilter', 'formatColumn'],
handler(params: PredicateDefHandlerContext) {
return params.value == 'JavaScript' || params.value == 'TypeScript';
},
},
{
id: 'last_ten_years',
label: 'Last Ten Years',
moduleScope: ['columnFilter'],
columnScope: {
DataTypes: ['date'],
},
handler(params: PredicateDefHandlerContext) {
const now = new Date();
const tenYearsAgo = new Date(now.setFullYear(now.getFullYear() - 10));
return new Date(params.value) > tenYearsAgo;
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
ColumnFilters: [
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'popular',
},
],
},
{
ColumnId: 'language',
Predicates: [
{
PredicateId: 'scripting',
},
],
},
{
ColumnId: 'created_at',
Predicates: [
{
PredicateId: 'last_ten_years',
},
],
},
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'style-all',
Scope: {All: true},
Rule: {
Predicates: [
{
PredicateId: 'scripting',
},
],
},
Style: {
ForeColor: 'White',
BackColor: 'Brown',
},
},
],
},
},
};
```
Users can create as many Custom (and System) Column Filters as required and AdapTable will automatically update AG Grid so that only rows which match **all** Filters will be displayed.
## Predicate Inputs
Custom Filters, like all Predicates, are able to accept **inputs** - so they can be given a dynamic argument.
**Example: Custom Filters with Inputs**
Creating Custom Filters that receive inputs
- This demo creates a Custom Filters that receives an input
- `Long String` has a `columnScope` of String columns, and receives a number input which verifies if the string is big or not
- Create a Column Filter on the `Language` Column using the `Long String` Custom Predicate and an input of 5: note that the 2 rows with HTML will be filtered out
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Filter Inputs',
predicateOptions: {
customPredicateDefs: [
{
id: 'long_string',
label: 'Long String',
columnScope: {DataTypes: ['text']},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
if (params.inputs) {
const input = params.inputs[0];
return (params.value as String).length > input;
}
return false;
},
inputs: [{type: 'number'}],
toString: ({inputs}) => `cell length > ${inputs[0]}`,
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['ColumnFilter'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'description',
'pushed_at',
'github_watchers',
'open_issues_count',
'created_at',
'license',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Custom Time Filters
Custom Filters are useful when you want to filter a Date Colum using only Time.
AdapTable provides a large number of System Filters but they all operate on a Date, not the Time portion only.
This is particularly useful if you have a "Day Activity Grid" which just displays entries for a single day
**Example: Custom Filters using Time**
Creating Custom Filters will filter on Time
- This demo creates 2 Custom Filters that use Time (both have `columnScope` of the `Pushed` column which we have changed to just show Times for today):
- `Overnight` returns true if the time in the Column is between midnight and the start of the day (9am)
- `Recent` receives a numeric input and returns true if the value is within the inputted number of hours
- Note: we also removed some Date System Predicates to make it easier to see the 2 Custom Predicates
- Run Column Filter on `Pushed` Column using `Midnight` Custom Predicate and note only values before 9am appear
- Run Column Filter on `Pushed` Column using `Recent` Custom Predicate and an input of 5 and note: only rows with a value in last 5 hours are displayed
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
SystemFilterPredicateIds,
SystemPredicatesContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Filter using Time',
predicateOptions: {
customPredicateDefs: [
{
id: 'overnight',
label: 'Overnight',
columnScope: {ColumnIds: ['pushed_at']},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
const midnight = new Date();
midnight.setHours(0, 0, 0, 0);
const startofDay: Date = new Date();
startofDay.setHours(9);
return params.value > midnight && params.value < startofDay;
},
toString: () => `between midnight and 9 am`,
},
{
id: 'recent',
label: 'Recent',
icon: {
name: 'schedule',
},
columnScope: {ColumnIds: ['pushed_at']},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
if (params.inputs) {
const input = params.inputs[0];
const cellDate: Date = params.value as Date;
const testDate: Date = new Date(
new Date().setHours(new Date().getHours() - input)
);
return cellDate > testDate;
}
return false;
},
inputs: [{type: 'number'}],
toString: ({inputs}) => `Date in last ${inputs[0]} hours`,
},
],
systemFilterPredicates: (context: SystemPredicatesContext) => {
return context.systemPredicateDefs
.map(predicate => predicate.id)
.filter(predicateId => {
return ![
'ExcludeValues',
'Blanks',
'NonBlanks',
'ThisQuarter',
'ThisYear',
'InPast',
'InFuture',
'Before',
'NotOn',
'NextWorkDay',
'LastWorkDay',
].includes(predicateId);
}) as SystemFilterPredicateIds;
},
},
initialState: {
Theme: {CurrentTheme: 'dark'},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['ColumnFilter'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'pushed_at',
'github_stars',
'github_watchers',
'open_issues_count',
'created_at',
'license',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-pushed_at',
Scope: {
ColumnIds: ['pushed_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy, H:mm',
},
},
},
],
},
},
};
```
```ts
export const pushedDate: Date = new Date();
export const rowData = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 2)
).setMinutes(new Date().getMinutes() - 20),
homepage: 'https://reactjs.org',
github_stars: 179429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
history: [27, 5, 13, 25, 12, 17, 11, 27],
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 5)
).setMinutes(new Date().getMinutes() - 11),
homepage: 'https://angular.io',
github_stars: 78348,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
history: [22, 28, 17, 25, 26, 20, 2, 30, 17, 19, 12, 9, 25, 22, 18],
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 1)
).setMinutes(new Date().getMinutes() - 3),
homepage: 'http://vuejs.org',
github_stars: 191435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
history: [22, 22, 24, 18, 11, 28],
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 7)
).setMinutes(new Date().getMinutes() - 32),
homepage: 'https://svelte.dev',
github_stars: 53935,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
history: [16, 21, 3, 1, 1, 11, 30, 20, 27, 18],
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 1)
).setMinutes(new Date().getMinutes() - 25),
homepage: 'https://alpinejs.dev',
github_stars: 19338,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
history: [15, 13, 26, 8, 19, 12, 25, 12],
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date(new Date().setHours(new Date().getHours())).setMinutes(
new Date().getMinutes() - 55
),
homepage: 'https://lit.dev',
github_stars: 9752,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
history: [17, 16, 23, 16, 3, 7],
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 3)
).setMinutes(new Date().getMinutes() - 9),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 11049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
history: [
5, 10, 12, 21, 13, 15, 17, 13, 22, 2, 13, 10, 11, 5, 5, 7, 29, 16,
],
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 2)
).setMinutes(new Date().getMinutes() - 41),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
history: [
30, 19, 4, 25, 24, 19, 29, 20, 29, 19, 28, 13, 27, 2, 7, 7, 21, 25, 23,
15,
],
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 1)
).setMinutes(new Date().getMinutes() - 20),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
history: [25, 17, 13, 5, 2, 18, 26, 11, 23, 23],
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 1)
).setMinutes(new Date().getMinutes() - 47),
homepage: 'https://solidjs.com',
github_stars: 13119,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 23,
history: [14, 22, 5, 13, 5, 30, 28, 15, 19, 11, 28, 24, 4, 2, 10, 30],
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 2)
).setMinutes(new Date().getMinutes() - 19),
homepage: 'https://mithril.js.org',
github_stars: 13064,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
history: [25, 18, 2, 23, 19],
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 9)
).setMinutes(new Date().getMinutes() - 38),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
history: [1, 7, 3, 3, 3, 22, 1, 12, 16, 15, 22],
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 2)
).setMinutes(new Date().getMinutes() - 22),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
history: [5, 6, 25, 7, 17, 6, 19, 27, 21, 5, 18],
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 11)
).setMinutes(new Date().getMinutes() - 33),
homepage: 'http://backbonejs.org',
github_stars: 27840,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
history: [
25, 26, 4, 14, 6, 22, 1, 4, 24, 28, 6, 28, 13, 22, 24, 8, 8, 8, 8, 27,
],
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 9)
).setMinutes(new Date().getMinutes() - 48),
homepage: 'http://knockoutjs.com/',
github_stars: 10122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
history: [23, 19, 6, 28, 5],
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 2)
).setMinutes(new Date().getMinutes() - 54),
homepage: 'https://redwoodjs.com',
github_stars: 10334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
history: [1, 21, 16, 8, 9, 13],
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 5)
).setMinutes(new Date().getMinutes() - 20),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
history: [10, 13, 12, 22, 4, 14, 27, 11, 18, 9, 21, 12],
},
{
id: 26316966,
name: 'cyclejs',
full_name: 'cyclejs/cyclejs',
html_url: 'https://github.com/cyclejs/cyclejs',
description:
'A functional and reactive JavaScript framework for predictable code',
created_at: new Date('2014-11-07T11:28:45').toDateString(),
updated_at: new Date('2021-12-20T06:39:49').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 6)
).setMinutes(new Date().getMinutes() - 7),
homepage: 'http://cycle.js.org',
github_stars: 9999,
language: 'TypeScript',
forks_count: 421,
open_issues_count: 102,
license: 'MIT License',
topics: [
'cyclejs',
'framework',
'functional-programming',
'hacktoberfest',
'javascript',
'reactive-programming',
'rxjs',
'typescript',
],
github_watchers: 205,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 563,
open_pr_count: 26,
closed_pr_count: 301,
week_issue_change: -2,
history: [27, 19, 25, 1, 17, 16, 9, 17, 1, 25, 24, 13, 26, 7, 12, 7, 5],
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: new Date('2021-12-20T09:02:15').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 0)
).setMinutes(new Date().getMinutes() - 45),
homepage: 'https://preactjs.com',
github_stars: 30538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
history: [
18, 3, 17, 22, 11, 26, 6, 1, 21, 16, 12, 13, 15, 19, 11, 12, 10, 21, 3,
],
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 7)
).setMinutes(new Date().getMinutes() - 11),
homepage: 'https://riot.js.org',
github_stars: 14597,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
history: [[26, 30, 10, 4, 5, 29, 8, 8, 2, 28, 17, 10, 27, 18, 8, 20]],
},
{
id: 121594173,
name: 'aurelia',
full_name: 'aurelia/aurelia',
html_url: 'https://github.com/aurelia/aurelia',
description:
'Aurelia 2, a standards-based, front-end framework designed for high-performing, ambitious applications.',
created_at: new Date('2018-02-15T05:22:58').toDateString(),
updated_at: new Date('2021-12-19T04:23:43').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 12)
).setMinutes(new Date().getMinutes() - 1),
homepage: '',
github_stars: 1142,
language: 'TypeScript',
forks_count: 121,
open_issues_count: 143,
license: 'MIT License',
topics: [
'aurelia',
'cordova',
'cross-platform',
'electron',
'framework',
'frontend',
'html',
'javascript',
'javascript-framework',
'mobile',
'pwa',
'single-page-applications',
'spa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 66,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 214,
open_pr_count: 17,
closed_pr_count: 959,
week_issue_change: 32,
history: [13, 6, 10, 15, 16, 30, 25, 1],
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 3)
).setMinutes(new Date().getMinutes() - 9),
homepage: 'https://nextjs.org',
github_stars: 78446,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
history: [30, 5, 1, 5, 18, 2, 13, 25, 27, 26, 20, 25, 18, 35],
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 6)
).setMinutes(new Date().getMinutes() - 4),
homepage: 'https://nuxtjs.org',
github_stars: 38997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
history: [
30, 4, 6, 28, 17, 30, 30, 20, 7, 26, 17, 4, 6, 3, 21, 24, 27, 30, 6, 5,
],
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 2)
).setMinutes(new Date().getMinutes() - 15),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
history: [29, 30, 28, 20, 1, 24],
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date(
new Date().setHours(new Date().getHours() - 4)
).setMinutes(new Date().getMinutes() - 47),
homepage: 'https://quasar.dev',
github_stars: 20095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
history: [26, 12, 7, 13, 17, 18, 20, 1, 28, 23, 22, 2, 2, 22, 18, 29, 2],
},
];
```
## Ordering Custom Predicates
By default Custom Predicates will be positioned at the bottom of the list, after all the System Predicates.
However it is possible to leverage the `systemFilterPredicates` property in Predicate Options to set Custom Predicates alongside System Predicates.
**Example: Ordering Custom Filters**
Ordering Custom Predicates provided for Filters
- In this example we create 2 Custom Predicates for Numeric Files (and apply Filters using them):
- `Greater Than or Equals` - with a Filter on the `Github Stars` Column
- `Less Than or Equals` - with a Filter on the `Github Watchers` Column
- We leverage the `systemFilterPredicates` property in Predicate Options to places the 2 Custom Predicates **inside** the System Predicates
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
SystemFilterPredicateIds,
SystemPredicatesContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
function insertPredicateAfter(
predicateIds: string[],
afterPredicateId: string,
predicateIdToInsert: string
): string[] {
const afterIndex = predicateIds.indexOf(afterPredicateId);
if (afterIndex === -1 || predicateIds.includes(predicateIdToInsert)) {
return predicateIds;
}
return [
...predicateIds.slice(0, afterIndex + 1),
predicateIdToInsert,
...predicateIds.slice(afterIndex + 1),
];
}
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Filter Predicates with Ordering',
predicateOptions: {
customPredicateDefs: [
{
id: 'greaterThanOrEqualTo',
extends: 'GreaterThan',
label: 'Greater Than or Equals',
icon: {name: 'greater-than-or-equal'},
handler({value, inputs}: PredicateDefHandlerContext) {
return Number(value) >= Number(inputs?.[0] ?? 0);
},
toString: ({inputs}) => `>= ${inputs[0] ?? ''}`,
shortcuts: ['>='],
},
{
id: 'lessThanOrEqualTo',
extends: 'LessThan',
label: 'Less Than or Equals',
icon: {name: 'less-than-or-equal'},
handler({value, inputs}: PredicateDefHandlerContext) {
return Number(value) <= Number(inputs?.[0] ?? 0);
},
toString: ({inputs}) => `<= ${inputs[0] ?? ''}`,
shortcuts: ['<='],
},
],
systemFilterPredicates: (context: SystemPredicatesContext) => {
const columnIds =
context.adaptableApi.columnScopeApi.getColumnIdsInScope(
context.columnScope
) ?? [];
const isNumericColumn = columnIds.some(columnId =>
context.adaptableApi.columnApi.hasNumberDataType(columnId)
);
let predicateIds = context.systemPredicateDefs.map(
predicate => predicate.id
);
if (isNumericColumn) {
predicateIds = insertPredicateAfter(
predicateIds,
'GreaterThan',
'greaterThanOrEqualTo'
);
predicateIds = insertPredicateAfter(
predicateIds,
'LessThan',
'lessThanOrEqualTo'
);
}
return predicateIds as SystemFilterPredicateIds;
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'github_watchers',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
ColumnFilters: [
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'greaterThanOrEqualTo',
Inputs: [10000],
},
],
},
{
ColumnId: 'github_watchers',
Predicates: [
{
PredicateId: 'lessThanOrEqualTo',
Inputs: [5000],
},
],
},
],
},
],
},
},
};
```
## Referencing Other Columns
The `handler` property used when evaluating [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) is given the current row node in its context.
This allows you to create Custom Filters that reference other Columns in the Row as part of the evaluation.
**Example: Custom Filters accessing Other Columns**
Creating Custom Filters that look up values in other Columns
- This demo creates 2 Custom Filters that reference other Columns in the Row for its evaluation:
- `Big Stars` returns true for `Github Stars` Column if it is greater than 10,000 and `Github Watchers` is over 200
- `Success` returns true for `Closed Issues` Column if it is greater than the `Closed PRs` Column
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Filter Predicates Other Columns',
predicateOptions: {
customPredicateDefs: [
{
id: 'success',
label: 'Success',
columnScope: {
ColumnIds: ['closed_issues_count'],
},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
const framework: WebFramework = params.node.data;
const closedPrs = framework.closed_pr_count;
return params.value > closedPrs;
},
},
{
id: 'big_stars',
label: 'Big Stars',
columnScope: {
ColumnIds: ['github_stars'],
},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
const framework: WebFramework = params.node.data;
const watchers = framework.github_watchers;
return params.value > 10000 && watchers > 200;
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'closed_issues_count',
'closed_pr_count',
'language',
'github_stars',
'github_watchers',
'week_issue_change',
'open_pr_count',
'created_at',
'pushed_at',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
ColumnFilters: [
{
ColumnId: 'closed_issues_count',
Predicates: [
{
PredicateId: 'success',
},
],
},
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'big_stars',
},
],
},
],
},
],
},
},
};
```
## Overriding System Filters
In addition to providing new Custom Filters, developers can provide Custom Filters which override the System Predicates shipped by AdapTable.
Make sure that the Custom Predicate has the same `id` as the System Predicate it replaces
This replaces the implementation for the System Filter provided by AdapTable with the custom behaviour.
- The Custom Predicate is placed in the **same position** in the Filter List as the System Predicate it replaces
- The **icon** which is displayed in the Filter Predicate dropdown is that of the overridden System Predicate
See [Overriding System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md#overriding-system-predicates) for more information and a full, explanatory, demo
---
# Defining Column Filters
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-defining
- Column Filters are defined inside a Layout
- They can be defined in both Table and Pivot Layouts
Column Filters can be provided at design-time in given Layouts via [Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md).
This can include Column Filters which use System Predicates and those which use Custom Predicates.
- See [Defining Table Layouts](https://www.adaptabletools.com/docs/handbook-layouts-table/index.md) for details on defining Column Filters in Layouts
- The [System Predicate Guide](https://www.adaptabletools.com/docs/adaptable-predicate/index.md#system-and-custom-predicates) lists all the Predicates which AdapTable provides for Filters
- The [Custom Predicate Guide](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) shows Developers how to provide Custom Predicates which can then be used in Filters
### Defining Columns Filters in a Layout
Column Filters are provided in a Layout as follows:
Create a `ColumnFilters` property inside a Layout
This is an array with one item for each Column Filter to be provided
Supply the `ColumnId` for each Filter.
Specify which Predicate to use:
- The `PredicateId` property must always be supplied
- Provide `Inputs` if required by the chosen Predicate
A Column Filter can also reference a user-provided Custom Predicate.
Again, provide the `ColumnId` and the `PredicateId` property (and any inputs).
The Column in the Filter must be appropriate to the `columnScope` defined in the Predicate
Create the Predicate in `customPredicateDefs` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md).
Make sure that the `moduleScope` includes 'columnFilter' if you want to use it in a Column Filter and provide the appropriate `columnScope`.
AdapTableQL uses the `handler` function to evaluate and apply the filter.
See [Custom Filters Guide](https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters/index.md) and [Custom Predicate Defs](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) for full details
```ts [[1, 13, "ColumnFilters"],[2, 15, "ColumnId"],[2, 23, "ColumnId"],[2, 32, "ColumnId"], [3, 16, "Predicates"],[3, 24, "Predicates"],[3, 33, "Predicates"], [4, 43, "customPredicateDefs"]]
// Provide 3 Column Filters
// a. In (System Predicate) on currency Column for 'USD' and 'EUR'
// b. GreaterThan (System Predicate) on price Column
// c. 'post-takeover' (Custom Predicate) on orderDate Column
// The Custom Predicate is defined in Predicate Options
const adaptableOptions: AdaptableOptions = {
const initialState: InitialState = {
Layout:{
CurrentLayout: 'Filtered Layout',
Layouts: {
Name: 'Filtered Layout',
TableColumns: ['currency', 'orderData', 'github_watchers', 'price'],
ColumnFilters: [
{
ColumnId: 'currency',
Predicates: [
{
PredicateId: 'In',
Inputs: ['USD', 'EUR']
}]
},
{
ColumnId: 'price',
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['500']
}
],
},
{
ColumnId: 'orderDate',
Predicates: [
{
PredicateId: 'post_takeover'
}
],
},
],
}
},
predicateOptions: {
customPredicateDefs: [
{
id: 'post_takeover',
label: 'Post Takeover',
columnScope: { DataTypes: ['date'] },
moduleScope: ['columnFilter', 'alert'],
handler(params: PredicateDefHandlerContext) {
return (params.value as Date) > new Date('2019-09-21');
},
},
],
}
};
```
---
# The 'In' Column Filter Predicate
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-in-filter
- The `In` Filter is a special Column Filter that shows distinct Column Values
- It is available in both the Filter Bar and the Filter Form
- Each distinct value in the Column is displayed with a checkbox alongside it for selection
- Developers have great flexibility in populating and rendering this list
AdapTable provides an `In` (and associated `NotIn`) Predicate to enable filtering on multiple column values.
This Predicate is selected by choosing the `In` Filter option in the Filter Predicates dropdown
When this is selected AdapTable's [Filter Components](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) display a list of all **distinct items in the Column**, together with an associated Checkbox indicating whether that value should be included in the Filter.
AdapTable provides developers with flexible, fine-grained control over each distinct Column value.
## Custom Column Values
By default, AdapTable populates the `In` Filter dropdown by looping through all the values in AG Grid for the column, retrieving and then displaying the distinct items.
- AdapTable will ignore case sensitivity by default, e.g. will return "EUR" and "eur" as 2 separate items
- This can be changed by setting the `caseSensitivePredicates` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md) to _true_
Alternatively, developers can supply **bespoke values** to be displayed instead.
This is done by using the `customInFilterValues` property in [Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) which allows extremely flexible and fine-grained control over which values are displayed and how they are rendered.
- However this flexibilty can come with a **potential performance cost**, especially in Grids with large data sets
- Use with care when displaying or counting visible values, when Row Grouping is active - see below for more details
The `customInFilterValues` property also populates the `In` predicate in the [Query Builder](https://www.adaptabletools.com/docs/ui-query-builder/index.md) (used by [Grid Filter](https://www.adaptabletools.com/docs/handbook-grid-filter/index.md)).
This property is the equivalent of the `filterValueGetter` [used by AG Grid's Set Filter](https://www.ag-grid.com/javascript-data-grid/filter-set-filter-list/#supplying-filter-values), but which **AdapTable ignores**
### `customInFilterValues`
Provide custom list of values to display for "In" Predicate
[`InFilterValueResult[]`](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md)
Use this property to change the list of values shown by AdapTable when using the `In` Predicate.
The property is in the form of a function that
- receives a [`CustomInFilterValuesContext`](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md) object
- returns an [`InFilterValueResult`](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md) array.
The function can also be run asynchronously to return a `Promise` if required
Function Context
The `CustomInFilterValuesContext` object **received** by the function is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [currentSearchValue](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md#currentsearchvalue) | `string` | Current text in the IN Filter search box. |
| [defaultValues](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md#defaultvalues) | `Required<`[`InFilterValueInfo`](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md)`>[]` | Distinct Column values in natural (unsorted) row iteration order. |
| [orderedValues](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md#orderedvalues) | `Required<`[`InFilterValueInfo`](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md)`>[]` | Distinct Column values in the order they appear in the grid from top to bottom. |
| [previousFilterResult](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md#previousfilterresult) | [`InFilterValueResult`](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md) | The result returned by the previous invocation of `FilterOptions.customInFilterValues`, if any. |
| [sortedValues](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md#sortedvalues) | `Required<`[`InFilterValueInfo`](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md)`>[]` | Distinct Column values sorted by the Column's own sort direction (Asc / Desc). |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
The `defaultValues`, `orderedValues` & `sortedValues` properties are all of type [`InFilterValueInfo[]`](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md) defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [children](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md#children) | [`InFilterValueInfo`](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md)`[]` | |
| [count](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md#count) | `number` | How many times Item appears in the column |
| [isSelected](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md#isselected) | `boolean` | Whether Item is currently selected |
| [leafChildrenCount](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md#leafchildrencount) | `number` | For the grouping scenario, how many leafs are there under this item |
| [visible](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md#visible) | `boolean` | Whether Item is currently visible in Grid (i.e. in filtered rows) |
| [visibleCount](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md#visiblecount) | `number` | How many times Item appears in the column in filtered rows |
Function Return Object
The `InFilterValueResult` object **returned** by the function (as an array) is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [skipDefaultSearch](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md#skipdefaultsearch) | `boolean` | If true, AdapTable will not filter the list using the current search value |
| [values](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md#values) | [`InFilterValue`](https://www.adaptabletools.com/docs/reference/infiltervalue.md)`[]` | List of Items to display in the IN Column Filter |
The `skipDefaultSearch` property is used when providing a bespoke search (see [below](#suppressing-results-search))
The `values` property is of type [`InFilterValue`](https://www.adaptabletools.com/docs/reference/infiltervalue.md) defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [children](https://www.adaptabletools.com/docs/reference/infiltervalue.md#children) | [`InFilterValue`](https://www.adaptabletools.com/docs/reference/infiltervalue.md)`[]` | |
| [label](https://www.adaptabletools.com/docs/reference/infiltervalue.md#label) | `string` | Item's label |
| [level](https://www.adaptabletools.com/docs/reference/infiltervalue.md#level) | `number` | |
| [tooltip](https://www.adaptabletools.com/docs/reference/infiltervalue.md#tooltip) | `boolean \| string` | Tooltip for Item (if true, the label is used as tooltip) |
| [value](https://www.adaptabletools.com/docs/reference/infiltervalue.md#value) | `ValueType` | The value of Item being shown |
There are multiple potential use cases for custom values, the most common of which are described here.
In each demo we set the `defaultTextColumnFilter` in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) to _In_ for ease of access
### Values Count
A common preference is to indicate how frequently each distinct item appears in the Grid.
This is achieved by leveraging the `count` property in the function's context.
**Example: In Filter: Values Count**
Show a count of each item in In Filter
- This demo updates the Label to include the count of each item
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Values Count',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
return {
values: context.defaultValues.map((info: InFilterValueInfo) => {
return {
value: info.value,
label: `${info.label} (${info.count})`,
};
}),
};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'license',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Filtered Values Only
Another common use case is to list only values which are currently displayed in the Grid.
In other words to skip values that only appear in Rows which have been previously filtered out.
This means that values which are in **collapsed** Row Groups will still be included in the list
This is achieved by using the `visible` property provided by the function for each item.
**Example: In Filter: Only Visible Values**
Only show currently filtered values in In Filter
- This demo only lists values in In filter which are currently in the Grid (i.e. in filtered rows)
- Note: _HTML_ does not appear in the `Language` Column's filter as its not present in the (filtered) grid
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValue,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Visible Values',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
let returnValues: InFilterValue[] = context.defaultValues
.filter((info: InFilterValueInfo) => info.visible)
.map(info => {
return {
value: info.value,
label: info.label,
};
});
return {values: returnValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
ColumnFilters: [
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['25000'],
},
],
},
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Filtered Values Count
Some users wish to display the list of column values using both of the previous use cases, ie:
- only display values which are in currently filtered rows
- provide a count of those values - but using filtered rows only
This is achieved by using the 2 properties provided by the function:
- `visible` - which states **if** that item is visible anywhere currently in the grid
- `visibleCount` - how **often** that items appears currently in the Grid
**Example: In Filter: Only Visible Values with Count**
Only show currently filtered values in In Filter together with a Count
- This demo only lists values in In filter which are currently in the Grid (i.e. in filtered rows)
- It also provides a count for each item
- Click on the `Language` Column IN Filter to open the dropdown list of values
- Note: (1) _HTML_ does not appear as its not present in the (filtered) grid; (2) we see 9 and 11 as the 2 counts (matching the 11 currently filtered rows)
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValue,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Visible Values with Count',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
let returnValues: InFilterValue[] = context.defaultValues
.filter((info: InFilterValueInfo) => info.visible)
.map(info => {
return {
value: info.value,
label: `${info.label} (${info.visibleCount})`,
};
});
return {values: returnValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'license',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
ColumnFilters: [
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['25000'],
},
],
},
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Displaying Raw Value
AdapTable displays the Cell's Display Value in the Label it renders (though it still filters on the Raw value).
It is straightforward to render the Raw, (not Display) Value by simply displaying the value property as the label.
**Example: In Filter: Showing Raw Value**
Show an item's raw value in In Filter
- This demo updates the Label to show the Raw value in the `In` Filter
- We have added [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) of upper case to `text` Columns and 'K' to `Github Stars` - but all these columns show the raw value
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Raw Values',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
return {
values: context.defaultValues.map((info: InFilterValueInfo) => {
return {
value: info.value,
label: info.value,
};
}),
};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Multiplier: 0.001,
Suffix: 'K',
},
},
},
{
Name: 'formatColumn-text',
Scope: {
DataTypes: ['text'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'week_issue_change',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Custom Labels
The label provided by AdapTable can easily be changed if required, to display custom text.
**Example: In Filter: Custom Label**
Show a custom label for In Filter values
- This demo shows custom labels for the In filter
- All values in the `Language` Column have a custom label, as does "React" in the `Name` column
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Custom Label',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
let returnValues: InFilterValueInfo[] = [];
if (context.column.columnId === 'language') {
returnValues = context.defaultValues.map((info: InFilterValueInfo) => {
return {
value: info.value,
label: 'lang: ' + info.value,
};
});
} else if (context.column.columnId === 'name') {
returnValues = context.defaultValues.map((info: InFilterValueInfo) => {
return info.value === 'react'
? {
value: info.value,
label: 'React (default)',
}
: {
value: info.value,
label: info.value,
};
});
} else {
returnValues = context.defaultValues;
}
return {values: returnValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Sorted Values
By default the values are listed in the order they appear in the Grid's DataSource.
But the function's context also contains a `SortedValues` property which will display values using any **currently active** Column Sorts (including [Custom Sorts](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md)).
This is **not** the same as using Column's current values' order (see below how to do that)
- If there are multiple columns sorted, only the first column will display items in the same order as in the Grid
- Other sorted Columns will display values according to the "natural" Sort Order (which may be different to the Grid)
**Example: In Filter: Sorted Values**
Sorting values in In Filter
- This demo shows the In Filter displaying values based on the Sort Order defined in the Layout
- The `Name` column has an Ascending Sort
- The `Language` column has an Descending Sort
- The `Issue Change` column has a [Custom Sort](https://www.adaptabletools.com/docs/handbook-custom-sorting/index.md) applied
- Note: Because `Name` is the first sorted column it displays in same order as Grid; the other 2 columns show the sort order as if they were the first sorted column
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Sorted Values',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
return {values: context.sortedValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
},
},
customSortOptions: {
customSortComparers: [
{
name: 'Comparer-week_issue_change',
scope: {
ColumnIds: ['week_issue_change'],
},
comparer: (valueA: any, valueB: any) => {
return Math.abs(valueB) - Math.abs(valueA);
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
ColumnSorts: [
{
ColumnId: 'name',
SortOrder: 'Asc',
},
{
ColumnId: 'language',
SortOrder: 'Desc',
},
{
ColumnId: 'week_issue_change',
SortOrder: 'Asc',
},
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Ordered Values
As noted above, by default the values in the list are displayed in the order they appear in the Grid's DataSource, and we provide a `SortedValues` property which will leverage any currently active Column Sorts.
There is also an option to display values **in the same order** as they are currently displayed in the Grid.
This is done using the `OrderedValues` property, which will provide the order for **any** column (irrespective of whether it is currently sorted)
**Example: In Filter: Ordered Values**
Ordering values in In Filter
- This demo shows the In Filter displaying values based on their Current Order
- The `Name` column has a Column Sort - and the In filter list reflects that order
- However other Columns (e.g. `Issue Change` and `Github Watchers`) display their current order (even though they are not sorted)
- Change the `Name` column from an ascending to descending sort, and note how `Issue Change` and `Github Watchers` columns show their current (i.e. changed) order
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Ordered Values',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
return {values: context.orderedValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
ColumnSorts: [
{
ColumnId: 'name',
SortOrder: 'Asc',
},
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Tooltip
It is possible to display a Tooltip in the In Filter if required.
All that is needed is to add `tooltip` to the return object, which can be done in 2 ways:
- setting it to `true` - displays the label also as a tooltip
- providing a custom string value to use as the tooltip
This allows you to provide a tooltip only if the value is more than a particular number of characters
**Example: In Filter: Showing a Tooltip**
Displaying a tooltip in In Filter
- In this example we display a tooltip when using the `In` Filter
- For string columns we show the standard tooltip, and for other columns we append the word 'VALUE' in the tooltip
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Show Tooltip',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
return {
values: context.defaultValues.map((info: InFilterValueInfo) => {
return {
value: info.value,
label: info.label,
tooltip:
context.column.dataType === 'text'
? true
: 'VALUE: ' + info.label,
};
}),
};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
defaultDateColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
### Extra Predicates
The list of custom Column values can be supplemented by adding other Predicates.
All that is required is to add the name of the Predicate to the default list provided by the function.
Common use cases include adding `Blanks` Predicate, or `Positive` and `Negative` Predicates to number columns
**Example: In Filter: Adding System Predicates**
Add System and Custom Predicates to filtered values in In Filter
- This demo shows how to include System Predicates in the `In` Filter's list of values:
- The `Issue Change` column adds 2 System Predicates: `Positive` and `Negative`
- The `Blanks` and `NonBlanks` System Predicates are added to any column which contains empty values (e.g. `Created` or `License`) - with custom labels ("Empty" and "Not Empty") applied
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Adding System Predicates',
predicateOptions: {},
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
let returnValues: InFilterValueInfo[] = [];
const blanks = ['', null, undefined];
// Add Positive & Negative System Predicates for Issue Change Column
if (context.column.columnId === 'week_issue_change') {
returnValues = [
{
label: 'Positive',
value: 'Positive',
},
{
label: 'Negative',
value: 'Negative',
},
...context.defaultValues,
];
}
// Add Blanks System Predicate for any Column which contains empty values
else if (
context.defaultValues.some((item: InFilterValueInfo) =>
blanks.includes(item.value)
)
) {
returnValues = [
{
label: 'Empty',
value: 'Blanks',
},
{
label: 'Not Empty',
value: 'NonBlanks',
},
...context.defaultValues,
];
}
// Return default list for all other columns
else returnValues = context.defaultValues;
return {values: returnValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
defaultDateColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'created_at',
'pushed_at',
'license',
'open_pr_count',
'closed_issues_count',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
export const rowData = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 8794429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
// has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: '',
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78548,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: undefined,
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
// has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: '',
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 7912435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: null,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: 0,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: '',
updated_at: '',
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 539735,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: undefined,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: '',
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 938,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: null,
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 0,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: '',
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 97952,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: '',
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 118049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: '',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: '',
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 0,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date('2021-12-19T21:06:01').toDateString(),
homepage: 'https://solidjs.com',
github_stars: 819,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 0,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 130164,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 278940,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: 0,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: '',
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 106122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date('2021-12-20T00:37:09').toDateString(),
homepage: 'https://redwoodjs.com',
github_stars: 103334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: '',
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 26316966,
name: 'cyclejs',
full_name: 'cyclejs/cyclejs',
html_url: 'https://github.com/cyclejs/cyclejs',
description:
'A functional and reactive JavaScript framework for predictable code',
created_at: new Date('2014-11-07T11:28:45').toDateString(),
updated_at: '',
pushed_at: new Date('2021-12-17T11:03:37').toDateString(),
homepage: 'http://cycle.js.org',
github_stars: 99499,
language: 'TypeScript',
forks_count: 421,
open_issues_count: 102,
license: 'MIT License',
topics: [
'cyclejs',
'framework',
'functional-programming',
'hacktoberfest',
'javascript',
'reactive-programming',
'rxjs',
'typescript',
],
github_watchers: 205,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 563,
open_pr_count: 26,
closed_pr_count: 301,
week_issue_change: -2,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: '',
pushed_at: new Date('2021-12-17T23:21:58').toDateString(),
homepage: 'https://preactjs.com',
github_stars: 3025538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date('2021-12-17T20:09:25').toDateString(),
homepage: 'https://riot.js.org',
github_stars: 145997,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 121594173,
name: 'aurelia',
full_name: 'aurelia/aurelia',
html_url: 'https://github.com/aurelia/aurelia',
description:
'Aurelia 2, a standards-based, front-end framework designed for high-performing, ambitious applications.',
created_at: new Date('2018-02-15T05:22:58').toDateString(),
updated_at: new Date('2021-12-19T04:23:43').toDateString(),
pushed_at: new Date('2021-11-28T16:21:43').toDateString(),
homepage: '',
github_stars: 987,
language: 'TypeScript',
forks_count: 121,
open_issues_count: 143,
license: 'MIT License',
topics: [
'aurelia',
'cordova',
'cross-platform',
'electron',
'framework',
'frontend',
'html',
'javascript',
'javascript-framework',
'mobile',
'pwa',
'single-page-applications',
'spa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 66,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 214,
open_pr_count: 17,
closed_pr_count: 959,
week_issue_change: 0,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date('2021-12-20T08:21:58').toDateString(),
homepage: 'https://nextjs.org',
github_stars: 7884046,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date('2021-12-20T08:05:15').toDateString(),
homepage: 'https://nuxtjs.org',
github_stars: 389997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: '',
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 210095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
Additionally the `In` Filter can display user-defined [Custom Predicates](https://www.adaptabletools.com/docs/handbook-column-filter-custom-filters/index.md).
**Example: In Filter: Adding Custom Predicates**
Add System and Custom Predicates to filtered values in In Filter
- This demo shows how to include Custom Predicates in the `In` Filter's list of values:
- The `Name` column adds 2 Custom Predicates: `Favourites` and `Non Favourites`
- The `Github Stars` column adds the `Popular` Custom Predicate
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Adding Custom Predicates',
predicateOptions: {
customPredicateDefs: [
{
id: 'favourites',
label: 'Favourites',
columnScope: {ColumnIds: ['name']},
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return ['react', 'angular', 'vue'].includes(context.value as string);
},
},
{
id: 'non_favourites',
label: 'Non Favourites',
columnScope: {ColumnIds: ['name']},
moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'],
handler(context: PredicateDefHandlerContext) {
return !['react', 'angular', 'vue'].includes(context.value as string);
},
},
{
id: 'popular',
label: 'Popular',
columnScope: {
ColumnIds: ['github_stars'],
},
moduleScope: ['columnFilter'],
handler(params: PredicateDefHandlerContext) {
const githubStarsCount: number = params.node.data.github_stars;
return githubStarsCount > 50000;
},
},
],
},
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
let returnValues: InFilterValueInfo[] = [];
// Add Favourites & Non Favourites Custom Predicates for Name Column
if (context.column.columnId === 'name') {
returnValues = [
{
label: 'Favourites',
value: 'favourites',
},
{
label: 'Non Favourites',
value: 'non_favourites',
},
...context.defaultValues,
];
}
// Add Popular Custom Predicate for Github Stars Column
else if (context.column.columnId === 'github_stars') {
returnValues = [
{
label: 'Popular',
value: 'popular',
},
...context.defaultValues,
];
}
// Return default list for all other columns
else {
returnValues = context.defaultValues;
}
return {values: returnValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
defaultDateColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Date Columns
For Date columns, AdapTable switches to a **Tree**, rather than flat, structure.
This displays years, months and dates in order, allowing users to select larger groups of days (e.g a whole year).
- It is possible to choose **not** to display the Tree and instead list the distinct dates contained in the Column
- This is done by returning the `orderedValues` property in the `customInFilterValues` function
### Filtering on Time
By default AdapTable will **not** evaluate Column Filters using time.
The Tree will show a single date, and all entries in that 24 hour period will be displayed if the date is selected.
However time can be also be included when evaluating a Date Column Filter if that is required.
This is done by setting the `evaluateInPredicateUsingTime` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md#predicate-options) to _true_.
- The property can return a simple boolean value to set time-based evaluation for all Date columns
- Or, alernatively, developers can provide a function which will decide on a per-Column basis
When this happens, the Tree will show a separate item for each distinct time-related cell value in the column.
**Example: In Filter: Date Columns**
In Filter showing Dates as a Tree structure
- In this example we have set all Date Columns to show the `In` Filter by default
- We have provided a function implementation for the `evaluateInPredicateUsingTime` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md#predicate-options) which returns _true_ only for the `Created` column
- We have also decided to show not to display the Tree, and instead show a list of distinct values, for the `Updated` column
- Open the `In` Filter for the `Created` Column and navigate to 3 April 2009: note that 3 different time values are displayed, each of which can be selected separately
- Open the `In` Filter for the `Pushed` Column and navigate to 19 May 2020: note that no different time values are displayed, but selecting that date results in 3 rows being displayed in the Grid
- Open the `In` Filter for the `Updated` Column and note that you see a list of values rather than the Tree
```ts
import {
AdaptableColumnContext,
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Date Columns',
predicateOptions: {
evaluateInPredicateUsingTime: (context: AdaptableColumnContext) => {
return context.column.columnId == 'created_at';
},
},
filterOptions: {
columnFilterOptions: {
defaultDateColumnFilter: 'In',
},
customInFilterValues: (context: CustomInFilterValuesContext) => {
if (context.column.columnId === 'updated_at') {
return {values: context.orderedValues};
}
return {values: context.defaultValues};
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-date',
Scope: {
DataTypes: ['date'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy, hh:mm:ss',
},
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'created_at',
'github_stars',
'pushed_at',
'open_pr_count',
'updated_at',
'closed_issues_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```ts
export interface WebFramework {
id: number;
name: string;
full_name?: string;
html_url?: string;
description: string;
created_at: string;
updated_at: string;
pushed_at: string;
homepage?: string;
github_stars: number;
language: string;
forks_count?: number;
open_issues_count: number;
license: string;
topics?: string[];
github_watchers: number;
has_projects: boolean;
has_wiki: boolean;
has_pages: boolean;
closed_issues_count: number;
open_pr_count: number;
closed_pr_count: number;
week_issue_change: number;
}
export const rowData: WebFramework[] = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2009-04-03T11:05:19').toISOString(),
updated_at: new Date('2021-12-20T09:03:49').toISOString(),
pushed_at: new Date('2021-12-19T14:34:59').toISOString(),
homepage: 'https://reactjs.org',
github_stars: 179429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2009-04-03T21:12:21').toISOString(),
updated_at: new Date('2021-12-20T08:37:07').toISOString(),
pushed_at: new Date('2021-12-19T21:54:01').toISOString(),
homepage: 'https://angular.io',
github_stars: 78348,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toISOString(),
updated_at: new Date('2021-12-20T08:47:06').toISOString(),
pushed_at: new Date('2021-12-20T08:10:16').toISOString(),
homepage: 'http://vuejs.org',
github_stars: 191435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toISOString(),
updated_at: new Date('2021-12-20T08:56:37').toISOString(),
pushed_at: new Date('2021-12-19T14:53:30').toISOString(),
homepage: 'https://svelte.dev',
github_stars: 53935,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toISOString(),
updated_at: new Date('2021-12-20T08:12:43').toISOString(),
pushed_at: new Date('2021-12-14T16:02:26').toISOString(),
homepage: 'https://alpinejs.dev',
github_stars: 19338,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toISOString(),
updated_at: new Date('2021-12-20T07:20:35').toISOString(),
pushed_at: new Date('2021-12-17T03:45:26').toISOString(),
homepage: 'https://lit.dev',
github_stars: 9752,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toISOString(),
updated_at: new Date('2021-12-20T07:20:01').toISOString(),
pushed_at: new Date('2021-12-17T20:47:34').toISOString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 11049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toISOString(),
updated_at: new Date('2021-12-19T07:57:31').toISOString(),
pushed_at: new Date('2021-12-20T07:15:54').toISOString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toISOString(),
updated_at: new Date('2021-12-20T05:46:50').toISOString(),
pushed_at: new Date('2021-12-16T21:15:17').toISOString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toISOString(),
updated_at: new Date('2021-12-20T08:29:47').toISOString(),
pushed_at: new Date('2021-12-19T21:06:01').toISOString(),
homepage: 'https://solidjs.com',
github_stars: 13119,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 23,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toISOString(),
updated_at: new Date('2021-12-20T03:17:55').toISOString(),
pushed_at: new Date('2021-11-24T10:16:47').toISOString(),
homepage: 'https://mithril.js.org',
github_stars: 13064,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toISOString(),
updated_at: new Date('2021-12-20T06:13:48').toISOString(),
pushed_at: new Date('2021-12-17T16:50:04').toISOString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toISOString(),
updated_at: new Date('2021-12-19T05:05:03').toISOString(),
pushed_at: new Date('2021-12-07T22:20:44').toISOString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toISOString(),
updated_at: new Date('2021-12-19T05:50:57').toISOString(),
pushed_at: new Date('2020-05-19T16:52:55').toISOString(),
homepage: 'http://backbonejs.org',
github_stars: 27840,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toISOString(),
updated_at: new Date('2021-12-18T17:20:52').toISOString(),
pushed_at: new Date('2020-05-19T21:37:24').toISOString(),
homepage: 'http://knockoutjs.com/',
github_stars: 10122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toISOString(),
updated_at: new Date('2021-12-20T01:41:55').toISOString(),
pushed_at: new Date('2020-05-19T09:21:47').toISOString(),
homepage: 'https://redwoodjs.com',
github_stars: 10334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toISOString(),
updated_at: new Date('2021-12-20T09:04:22').toISOString(),
pushed_at: new Date('2021-12-20T08:04:34').toISOString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 26316966,
name: 'cyclejs',
full_name: 'cyclejs/cyclejs',
html_url: 'https://github.com/cyclejs/cyclejs',
description:
'A functional and reactive JavaScript framework for predictable code',
created_at: new Date('2014-11-07T11:28:45').toISOString(),
updated_at: new Date('2021-12-20T06:39:49').toISOString(),
pushed_at: new Date('2021-12-17T11:03:37').toISOString(),
homepage: 'http://cycle.js.org',
github_stars: 9999,
language: 'TypeScript',
forks_count: 421,
open_issues_count: 102,
license: 'MIT License',
topics: [
'cyclejs',
'framework',
'functional-programming',
'hacktoberfest',
'javascript',
'reactive-programming',
'rxjs',
'typescript',
],
github_watchers: 205,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 563,
open_pr_count: 26,
closed_pr_count: 301,
week_issue_change: -2,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toISOString(),
updated_at: new Date('2021-12-20T09:02:15').toISOString(),
pushed_at: new Date('2021-12-17T23:21:58').toISOString(),
homepage: 'https://preactjs.com',
github_stars: 30538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toISOString(),
updated_at: new Date('2021-12-20T05:17:31').toISOString(),
pushed_at: new Date('2021-12-17T20:09:25').toISOString(),
homepage: 'https://riot.js.org',
github_stars: 14597,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 121594173,
name: 'aurelia',
full_name: 'aurelia/aurelia',
html_url: 'https://github.com/aurelia/aurelia',
description:
'Aurelia 2, a standards-based, front-end framework designed for high-performing, ambitious applications.',
created_at: new Date('2018-02-15T05:22:58').toISOString(),
updated_at: new Date('2021-12-19T04:23:43').toISOString(),
pushed_at: new Date('2021-11-28T16:21:43').toISOString(),
homepage: '',
github_stars: 1142,
language: 'TypeScript',
forks_count: 121,
open_issues_count: 143,
license: 'MIT License',
topics: [
'aurelia',
'cordova',
'cross-platform',
'electron',
'framework',
'frontend',
'html',
'javascript',
'javascript-framework',
'mobile',
'pwa',
'single-page-applications',
'spa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 66,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 214,
open_pr_count: 17,
closed_pr_count: 959,
week_issue_change: 32,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toISOString(),
updated_at: new Date('2021-12-20T08:57:47').toISOString(),
pushed_at: new Date('2021-12-20T08:21:58').toISOString(),
homepage: 'https://nextjs.org',
github_stars: 78446,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toISOString(),
updated_at: new Date('2021-12-20T08:27:45').toISOString(),
pushed_at: new Date('2021-12-20T08:05:15').toISOString(),
homepage: 'https://nuxtjs.org',
github_stars: 38997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toISOString(),
updated_at: new Date('2021-12-20T06:36:27').toISOString(),
pushed_at: new Date('2021-12-17T18:10:08').toISOString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toISOString(),
updated_at: new Date('2021-12-20T08:26:07').toISOString(),
pushed_at: new Date('2021-12-19T23:18:50').toISOString(),
homepage: 'https://quasar.dev',
github_stars: 20095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
## Suppressing Results Search
AdapTable automatically filters the displayed results in response to the user typing in the In Filter's search bar.
In other words typing 'b' will result in only values being displayed that contain 'b'.
This behaviour can be turned off so that AdapTable will do nothing if the user enters search text.
- This is particularly useful if you wish to [provide the Column values yourselves](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md), bypassing AdapTable completely
- You still receive the search term the user typed which you can leverage to refine your own internal algorithm
There are 2 frequent use cases where this might happen
- The user is using the [Server-Side Row Model](https://www.adaptabletools.com/docs/dev-guide-row-models-server-overview/index.md) or providing the list of items from the server for other reasons
- The user wishes to perform a different way of searching the results, e.g. evaluating using "starts with"
The Context for the function includes a `currentSearchValue` property which contains what was inputted by the user
In order to do this, the function's return object needs to include both properties:
- the replacement values that should be displayed (in place of those that AdapTable would otherwise list)
- the `skipDefaultSearch` property which should be set to _true_
**Example: In Filter: Suppressing Search**
Supressing Search in In Filter (enabling server valuation)
- This example shows how to suppress search for the `In` Filter; we provide 2 rules for the `Name` column:
- Typing '\*' will provide a small list of the top 5 Frameworks
- Typing in any other text will return those Frameworks which start with that letter
- In the `Name` Column, type in '\*' to see just 5 items; type in anything to see items that start with the search value
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Suppressing Search',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
if (context.column.columnId === 'name') {
console.log('suppressing search...');
let filterFn;
if (context.currentSearchValue === '*') {
const topFive = ['react', 'angular', 'vue', 'polymer', 'solid'];
filterFn = (x: {value: string; label: string}) => {
return topFive.includes(x.value);
};
} else {
filterFn = (x: {value: string; label: string}) => {
return x.value.startsWith(context.currentSearchValue);
};
}
const returnValues = context.defaultValues.filter(filterFn);
return {values: returnValues, skipDefaultSearch: true};
}
return {values: context.defaultValues};
},
columnFilterOptions: {
defaultTextColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## The `NotIn` Predicate
AdapTable also provides the `NotIn` Predicate.
This works in a very similar way to the `In` Predicate but, as the name implies, it **excludes** any selected values.
**Example: Not In Filter**
Excluding Column Values from the Filter
- This example contains 2 Columns Filters that use the `NotIn` Predicate:
- The `Name` Column shows any value except for "React" or "Angular"
- The `Language` Column shows any value except for "HTML"
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Not In Filter',
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'week_issue_change',
'github_stars',
'open_pr_count',
'created_at',
'closed_issues_count',
'pushed_at',
'closed_pr_count',
'has_projects',
'has_pages',
'updated_at',
'topics',
],
ColumnFilters: [
{
ColumnId: 'name',
Predicates: [
{
PredicateId: 'NotIn',
Inputs: ['React', 'Angular'],
},
],
},
{
ColumnId: 'language',
Predicates: [
{
PredicateId: 'NotIn',
Inputs: ['HTML'],
},
],
},
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Array Columns
AdapTable makes the In Filter the default Predicate for [Array Columns](https://www.adaptabletools.com/docs/dev-guide-aggrid-array-columns/index.md).
Each distinct item in a cell's array is listed separately, and all rows which contain that item are displayed.
**Example: In Filter: Arrays**
The In Predicate with Array Columns
- This example shows how AdapTable works with Array Columns in the In Filter.
- We have 2 columns that contain Array values - `Institutions` and `Awards` - and both are supplied with Column Filters
- Clear / edit the Column Filter for the `Institutions` and `Awards` columns
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'EmployeeId',
adaptableId: 'In Filter Arrays',
initialState: {
Dashboard: {
ModuleButtons: ['StyledColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Basic Layout',
Layouts: [
{
Name: 'Basic Layout',
TableColumns: [
'Name',
'Institutions',
'Year',
'Awards',
'Country',
'CountryCode',
'Email',
],
ColumnFilters: [
{
ColumnId: 'Institutions',
Predicates: [
{
PredicateId: 'In',
Inputs: ['Max Planck', 'Princeton', 'Geneva'],
},
],
},
{
ColumnId: 'Awards',
Predicates: [
{
PredicateId: 'In',
Inputs: [2012, 2019],
},
],
},
],
ColumnSizing: {
Name: {Width: 130},
Year: {Width: 80},
Country: {Width: 150},
CountryCode: {Width: 120},
Institutions: {Width: 350},
Email: {Width: 150},
Awards: {Width: 200},
},
},
],
},
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
headerName: 'Id',
field: 'EmployeeId',
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Name',
field: 'Name',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Year',
field: 'Year',
filter: true,
editable: false,
sortable: true,
cellDataType: 'number',
},
{
headerName: 'Institutions',
field: 'Institutions',
filter: true,
editable: false,
sortable: true,
cellDataType: 'textArray',
},
{
headerName: 'Country',
field: 'Country',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'CountryCode',
field: 'CountryCode',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Email',
field: 'Email',
filter: true,
editable: false,
sortable: true,
cellDataType: 'text',
},
{
headerName: 'Awards',
field: 'Awards',
filter: true,
editable: false,
sortable: true,
cellDataType: 'numberArray',
},
];
```
```ts
export const rowData = [
{
EmployeeId: 1,
Name: 'Giorgio Parisi',
Year: 2021,
Institutions: ['Sapienza', 'Columbia'],
Country: 'Italy',
CountryCode: 'ITA',
Email: 'giorgio.parisi@mail.com',
Awards: [2012, 2017, 2022],
},
{
EmployeeId: 2,
Name: 'Klaus Hasselman',
Year: 2021,
Institutions: ['Hamburg', 'Max Planck'],
Country: 'Germany',
CountryCode: 'DEU',
Email: 'klaus.hasselman@yahoo.com',
Awards: [2015, 2023],
},
{
EmployeeId: 3,
Name: 'Syukor Manabe',
Year: 2021,
Institutions: ['Princeton', 'Nagoya'],
Country: 'Japan',
CountryCode: 'JPN',
Email: 'syukor.manabe@outlook.com',
Awards: [2010, 2019, 2024],
},
{
EmployeeId: 4,
Name: 'Andrea Ghez',
Year: 2020,
Institutions: ['University of Cambridge'],
Country: 'United States',
CountryCode: 'USA',
Email: 'andrea.ghez@mail.com',
Awards: [2013, 2017, 2020, 2023],
},
{
EmployeeId: 5,
Name: 'Reinhard Genzel',
Year: 2020,
Institutions: ['Max Planck', 'Oxford University'],
Country: 'Germany',
CountryCode: 'DEU',
Email: 'reinhard.genzel@mail.com',
Awards: [2019],
},
{
EmployeeId: 6,
Name: 'Roger Penrose',
Year: 2020,
Institutions: ['Columbia', 'Princeton', 'Syracuse'],
Country: 'United Kingdom',
CountryCode: 'GBR',
Email: 'roger.penrose@yahoo.com',
Awards: [2014, 2015, 2025],
},
{
EmployeeId: 7,
Name: 'Didier Queloz',
Year: 2019,
Institutions: ['University of Cambridge', 'Geneva'],
Country: 'Switzerland',
CountryCode: 'CHE',
Email: 'didier.queloz@mail.com',
Awards: [2015, 2016, 2022],
},
{
EmployeeId: 8,
Name: 'Michel Mayor',
Year: 2019,
Institutions: ['Geneva', 'Columbia'],
Country: 'Switzerland',
CountryCode: 'CHE',
Email: 'michel.mayor@yahoo.com',
Awards: [2012, 2013],
},
{
EmployeeId: 9,
Name: 'Jim Peebles',
Year: 2019,
Institutions: ['Oxford University', 'Princeton'],
Country: 'United States',
CountryCode: 'USA',
Email: 'jim.peebles@outlook.com',
Awards: [2015, 2017, 2021, 2022, 2023],
},
];
```
## Performance Considerations
The `In` Filter is very powerful and offers great flexibility for users, enabling a huge range of use cases as can be seen above.
However this flexibility can come with a **potential performance cost**, especially in Grids with large data sets.
Use the `customInFilterValues` function **with great care** particularly in Columns with high numbers of distinct values
The following properties, in particular, can cause peformance issues if not used carefully:
- `visible` and `visibleCount` - in both cases, each distinct value needs to be evaluated individually, which is particularly expensive when [Row Grouping](https://www.adaptabletools.com/docs/handbook-grouping-rows/index.md) is active
- `orderedValues` can be a very timely operation
- AdapTable evaluates all these properties lazily (to ensure performance penalties are restricted to their actual use)
- In other words, these properties are only evaluated if they are expressly invoked in the function implementation
### Caching Results
To improve performance further, AdapTable **caches** each filter result, and then makes that available the next time the Column's In Filter is displayed, via the `previousFilterResult` property.
AdapTable will destroy the cache if relevant things change (e.g. the column's data updates or a new sort is applied)
This allows you to first check if there is a cached result, and if there is, to display that.
### Manually Applying Filters
Another option when using the `In` Filter with columns with a large numbers of records, is to turn on manually applying Column Filters.
When this property is set, the Filter is only evaluated when an `Apply` button is clicked, avoiding the list needing to be re-rendered on each click.
See [Manually Applying Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying/index.md) for more details
**Example: In Filter Performance**
Using In Filter with very big data
- This contains **100,000** rows and 20 columns (the data is sourced externally so takes 5-8 seconds to fetch and load)
- We have set the default Column Predicate to `In` for text, numeric and date columns
- We have provided an "expensive" implementation of visible count (ie. we only list currently visible items together with a count)
- However we first check to see if the values for the column are cached, and use that if they are
- Finally we set `manuallyApplyColumnFilter` to true (for all columns) so that we only evaluate the Filter when the Apply button is clicked
```ts
import {
AdaptableOptions,
CustomInFilterValuesContext,
InFilterValueInfo,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'In Filter Performance',
filterOptions: {
customInFilterValues: (context: CustomInFilterValuesContext) => {
// if previous result is cached, then display that
if (context.previousFilterResult) {
return context.previousFilterResult;
}
// show visible values only with count (the most expensive operation)
return {
values: context.defaultValues
.filter((info: InFilterValueInfo) => info.visible)
.map(info => {
return {
value: info.value,
label: `${info.label} (${info.visibleCount})`,
};
}),
};
},
columnFilterOptions: {
manuallyApplyColumnFilter: true,
defaultTextColumnFilter: 'In',
defaultNumericColumnFilter: 'In',
defaultDateColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['SettingsPanel'],
PinnedToolbars: ['Layout'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Table Layout',
Layouts: [
{
Name: 'Table Layout',
TableColumns: [
'id',
'prodName',
'company',
'price',
'amount',
'currency',
'orderDate',
'dueDate',
'lastName',
'firstName',
'origin',
'toAddress',
'invoiceNum',
'accountNum',
'department',
],
AutoSizeColumns: true,
},
{
Name: 'Grouped Layout',
TableColumns: [
'id',
'company',
'price',
'amount',
'currency',
'orderDate',
'dueDate',
'lastName',
'firstName',
'origin',
'toAddress',
'invoiceNum',
'accountNum',
'department',
],
AutoSizeColumns: true,
RowGroupedColumns: ['prodName'],
},
],
},
},
};
```
```ts
import {AdaptableReadyInfo} from '@adaptabletools/adaptable';
export const onAdaptableReady = async ({adaptableApi}: AdaptableReadyInfo) => {
const data = await fetchData();
adaptableApi.gridApi.loadGridData(data);
adaptableApi.columnApi.autosizeAllColumns();
};
const API_BASE = process.env.NEXT_PUBLIC_ORDERS_API_URL;
async function fetchData() {
const response = await fetch(`${API_BASE}/100k`);
return response.json();
}
```
```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';
import {columnDefs} from 'columnDefs';
export const gridOptions: GridOptions = {
theme: themeBalham,
defaultColDef: {
resizable: true,
sortable: true,
editable: true,
filter: true,
floatingFilter: true,
},
columnDefs: columnDefs,
sideBar: true,
suppressMenuHide: true,
cellSelection: true,
statusBar: {
statusPanels: [
{statusPanel: 'agTotalRowCountComponent', align: 'left'},
{statusPanel: 'agFilteredRowCountComponent'},
{
key: 'Center Panel',
statusPanel: 'AdaptableStatusPanel',
align: 'center',
},
],
},
};
```
```ts
import {ColDef} from 'ag-grid-enterprise';
export const columnDefs: ColDef[] = [
{
field: 'id',
cellDataType: 'number',
hide: true,
editable: false,
},
{
field: 'prodName',
headerName: 'Product Name',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'company',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'price',
cellDataType: 'number',
},
{
field: 'amount',
cellDataType: 'number',
},
{
field: 'currency',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'lastName',
headerName: 'Customer Last Name',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'firstName',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'origin',
headerName: 'Country of Origin',
cellDataType: 'text',
enableRowGroup: true,
},
{
field: 'toAddress',
headerName: 'Shipping Address',
cellDataType: 'text',
},
{
field: 'orderDate',
cellDataType: 'date',
},
{
field: 'dueDate',
cellDataType: 'date',
},
{
field: 'invoiceNum',
headerName: 'Invoice Number',
cellDataType: 'number',
},
{
field: 'accountNum',
headerName: 'Account Number',
cellDataType: 'text',
},
{
field: 'department',
cellDataType: 'text',
enableRowGroup: true,
},
];
```
---
# The 'In' Column Filter Predicate
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-in-predicate
This AdapTable Help Page [has moved here](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md)
---
# Manually Applying Column Filters
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-manually-applying
- Column Filtering in AdapTable can be configured so that Filters are only applied when a button is clicked
- This is particularly useful if you wish to use the IN filter or you are using the server side row model
By default Column Filters are applied as soon as they are created or edited, so users can see the results immediately.
However sometimes this behaviour can be unwelcome.
This is often the case when [evaluating Column Filters on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md), or the [In Filter](https://www.adaptabletools.com/docs/handbook-column-filter-in-filter/index.md) is being used
For this reason, AdapTable allows auto-evaluation of Column Filters to be turned off when necessary.
This is done via the `manuallyApplyColumnFilter` property in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md).
### `manuallyApplyColumnFilter`
Manually apply Column Filter only after a button is clicked
Set this property to *true* to stop AdapTable immediately evaluating Column Filter changes.
Instead an *Apply Filter* button will display in the Filter Form (and the Filter Bar will be disabled).
Only upon clicking this button, will the Column Filter be applied.
This property can be provided as a 'hard-coded' boolean value:
```ts {5}
// Don't apply Column Filters automatically but instead after a button is clicked
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions: {
manuallyApplyColumnFilter: false
}
}
};
```
Or via a boolean function which receives an [`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md) which simply contains the current Column:
| Property | Type | Description |
| --- | --- | --- |
| [column](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md#column) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md)`` | The current Column |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
```ts {5}
// Don't apply Column Filters automatically for string columns
const adaptableOptions: AdaptableOptions = {
filterOptions:{
columnFilterOptions = {
manuallyApplyColumnFilter: (context: AdaptableColumnContext) => {
return context.column.dataType === 'text';
},
}
}
};
```
In this scenario, AdapTable will not apply Column Filters immediately.
AdapTable will **disable the Filter Bar** for any Column where Manually-applying Filters is turned on
Instead 2 extra buttons are displayed in the Filter Form:
- `Apply Filter` - only when that button is clicked are Column Filters evaluated and applied
- `Reset Filter` - resets the Filters to what was previously applied (**not** the same as clearing)
**Example: Manually Apply Filters**
Manually Applying Column Filters
- In this example we set [manuallyApplyColumnFilter](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md) to *true* for String Columns
- As a result Column Filters in String Columns are not applied in the [Filter Form](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) automatically - only when the `Apply Filter` button is clicked
- Additionally, the [Filter Bar](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) is disabled for these Columns and the Filter Form opens instead
```ts
import {
AdaptableOptions,
AdaptableColumnContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Manually Apply Filter',
filterOptions: {
columnFilterOptions: {
manuallyApplyColumnFilter: (context: AdaptableColumnContext) => {
return context.column.dataType === 'text';
},
defaultTextColumnFilter: 'In',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
---
# System Filter Predicates
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-system-filters
- AdapTable provides multiple System Predicates available for use in Column Filters
- Developers are able to choose on a per-column basis which of these Predicates are available to their users
- They can also select the default Predicate (for each Column or DataType)
## Available System Filters
This is the full list of System Predicates shipped by AdapTable which are available for Column Filters:
All includes [array types](https://www.adaptabletools.com/docs/dev-guide-aggrid-array-columns/index.md) as well `number`, `text`, `date` and `boolean`
| [Predicate](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) | [Column Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) | No.of Inputs |
| ----------------------------------------------------------- | :-----------------------------------------------------------------------------: | :----------: |
| `Blanks` | All | 0 |
| `NonBlanks` | All | 0 |
| `In` | All | n |
| `NotIn` | All | n |
| `Equals` | number | 1 |
| `NotEquals` | number | 1 |
| `GreaterThan` | number | 1 |
| `LessThan` | number | 1 |
| `Positive` | number | 0 |
| `Negative` | number | 0 |
| `Zero` | number | 0 |
| `Between` | number | 2 |
| `NotBetween` | number | 2 |
| `Is` | text | 1 |
| `IsNot` | text | 1 |
| `Contains` | text | 1 |
| `NotContains` | text | 1 |
| `StartsWith` | text | 1 |
| `EndsWith` | text | 1 |
| `Regex` | text | 1 |
| `Today` | date | 0 |
| `Yesterday` | date | 0 |
| `Tomorrow` | date | 0 |
| `ThisWeek` | date | 0 |
| `ThisMonth` | date | 0 |
| `ThisQuarter` | date | 0 |
| `ThisYear` | date | 0 |
| `InPast` | date | 0 |
| `InFuture` | date | 0 |
| `Before` | date | 1 |
| `After` | date | 1 |
| `On` | date | 1 |
| `NotOn` | date | 1 |
| `NextWorkDay` | date | 0 |
| `LastWorkDay` | date | 0 |
| `WorkDay` | date | 0 |
| `Holiday` | date | 0 |
| `Range` | date | 2 |
| `True` | boolean | 0 |
| `False` | boolean | 0 |
### Filters By Column Data Type
Numeric Column Filters
- `Blanks`
- `NonBlanks`
- `In`
- `NotIn`
- `Equals`
- `NotEquals`
- `GreaterThan`
- `LessThan`
- `Positive`
- `Negative`
- `Zero`
- `Between`
- `NotBetween`
Text Column Filters
- `Blanks`
- `NonBlanks`
- `In`
- `NotIn`
- `Is`
- `IsNot`
- `Contains`
- `NotContains`
- `StartsWith`
- `EndsWith`
- `Regex`
Date Column Filters
- `Blanks`
- `NonBlanks`
- `In`
- `NotIn`
- `Today`
- `Yesterday`
- `Tomorrow`
- `ThisMonth`
- `ThisQuarter`
- `ThisYear`
- `InPast`
- `InFuture`
- `Before`
- `On`
- `NotOn`
- `NextWorkDay`
- `LastWorkDay`
- `WorkDay`
- `Holiday`
- `Range`
Boolean Column Filters
- `Blanks`
- `NonBlanks`
- `In`
- `NotIn`
- `True`
- `False`
## Limiting System Filters
By default all Predicates shipped by AdapTable are fully available in the Module to which they are entitled.
This means that all the Predicates listed above which can be used in Filtering will be available to users.
AdapTable provides the `systemFilterPredicates` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md) to override this if required.
### `systemFilterPredicates`
Which System Filter Predicates are available in AdapTable
The System Filter Predicates displayed by AdapTable can be limited using this property in 2 ways:
- **Providing a List** – The simplest way to set System Filters is to provide a List of the `PredicateIds` to display:
```ts {4}
// Only make 3 (of the many) System Filters available
const adaptableOptions: AdaptableOptions = {
predicateOptions: {
systemFilterPredicates: ['Positive', 'Today', 'Blanks'],
},
};
```
- **Providing a Function** – Alternatively this property can be a JavaScript function which returns a list of System Filters.
Using a Function enables you to provide different System Filter Predicates for different columns
The function receives a receives an object of type [`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md) which is defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [columnScope](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md#columnscope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Current Scope where Predicates are being used |
| [moduleScope](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md#modulescope) | [`PredicateModuleScope`](https://www.adaptabletools.com/docs/reference/predicatemodulescope.md) | Module for which Predicates are being retrieved |
| [systemPredicateDefs](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md#systempredicatedefs) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | AdapTable-provided System Predicate Definitions |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
The `columnScope` property always contains a single `ColumnIds` array with one item - the current *ColumnId*
```ts {5,6,7,8,9,10}
// Remove 4 System Filters from the List
const adaptableOptions: AdaptableOptions = {
predicateOptions: {
systemFilterPredicates: (context: SystemPredicatesContext) => {
return context.systemPredicateDefs
.map(predicate => predicate.id)
.filter(predicateId => {
return ['Contains', 'ThisWeek', 'ThisMonth', 'GreaterThan'].includes(
predicateId
);
}) as SystemFilterPredicateIds;
},
},
};
```
**Example: System Filters**
Configuring System Predicates in Filters
- This demo shows how to limit which System Filter Predicates are available in AdapTable by using the `systemFilterPredicates` property in [Predicate Options](https://www.adaptabletools.com/docs/adaptable-predicate-technical-reference/index.md)
- It provides a function which contains this logic:
- The Name Column will only display the `Contains`, `EndsWith` and `Regex` System Predicates
- All other Columns will show whichever of the `GreaterThan`, `LessThan`, `ThisMonth`, `ThisQuarter` and `In` System Predicates are relevant to that Column
### Expand to see how System Filters are limited
```ts
predicateOptions: {
systemFilterPredicates: (context: SystemPredicatesContext) => {
const scope: ColumnScope = context.columnScope;
const columnIdsInScope: string[] | undefined = context.adaptableApi.columnScopeApi.getColumnIdsInScope(scope);
return columnIdsInScope?.includes('name')
? ['Contains', 'EndsWith', 'Regex']
: ['Contains', 'GreaterThan', 'Equals', 'ThisMonth', 'Is', 'In'];
},
},
```
- Open the various filter dropdowns and see that there is a much reduced list of Filters available
- Open the `Name` dropdown and see that the list provided in the function just for that column is shown
```ts
import {
AdaptableOptions,
ColumnScope,
SystemPredicatesContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'System Filters',
predicateOptions: {
systemFilterPredicates: (context: SystemPredicatesContext) => {
const scope: ColumnScope = context.columnScope;
const columnIdsInScope: string[] | undefined =
context.adaptableApi.columnScopeApi.getColumnIdsInScope(scope);
return columnIdsInScope?.includes('name')
? ['Contains', 'EndsWith', 'Regex']
: ['Contains', 'GreaterThan', 'Equals', 'ThisMonth', 'Is', 'In'];
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'delete_row',
'language',
'github_stars',
'topics',
'license',
'created_at',
'has_wiki',
'updated_at',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
ColumnFilters: [
{
ColumnId: 'language',
Predicates: [
{
PredicateId: 'In',
Inputs: ['TypeScript', 'HTML'],
},
],
},
{
ColumnId: 'github_stars',
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [15000],
},
],
},
],
},
],
},
},
};
```
## Default Filter Predicates
AdapTable sets a default Filter Predicate to use for 4 Column Data Types.
However, each of these can be changed by using a relevant property in [Column Filter Options](https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference/index.md):
| Data Type | Options Property | Default | Available Values |
| --------- | ---------------------------- | ---------- | -------------------------------------------------------------------------- |
| text | `defaultTextColumnFilter` | `Contains` | `Is` `IsNot` `Contains` `NotContains` `In` `StartsWith` `EndsWith` `Regex` |
| numeric | `defaultNumericColumnFilter` | `Equals` | `GreaterThan` `LessThan` `Equals` `NotEquals` `In` |
| date | `defaultDateColumnFilter` | `On` | `After` `Before` `On` `NotOn` `In` |
| array | `defaultArrayColumnFilter` | `In` | `In` `NotIn` `Blanks` `NonBlanks` |
It is also possible to set a **different** default Predicate to display in the Filter Bar and the Filter Form
Each property offers two types of return value:
- a Predicate (relevant to the data type) directly
- a function which receives an [`DefaultPredicateFilterContext`](https://www.adaptabletools.com/docs/reference/defaultpredicatefiltercontext.md) object, and returns the Predicate
This is particularly useful in the [Filter Bar](https://www.adaptabletools.com/docs/handbook-column-filter-components/index.md) as it sets the Predicate that is displayed by default for the Column
**Example: Default Predicates for Filters**
Setting new default Predicates for Filters
- This example sets the 4 different data-type related Default Predicate properties:
- `defaultNumericColumnFilter` - **GreaterThan** for *Filter Bar* and **LessThan** for *Filter Form* (provided hard-coded for both, so is same for all numeric columns)
- `defaultTextColumnFilter` - **StartsWith** for all string columns except `Language` which is **In**
- `defaultDateColumnFilter` - **Before** for `Created` and `Updated` columns, and **After** for all other date columns
- `defaultArrayColumnFilter` - **NotIn** (provided hard-coded so is same for all array columns)
```ts
import {
AdaptableOptions,
DefaultPredicateFilterContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Filter Default Predicate',
filterOptions: {
columnFilterOptions: {
defaultNumericColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.filterComponent === 'FilterBar'
? 'GreaterThan'
: 'LessThan';
},
defaultTextColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'language' ? 'In' : 'StartsWith';
},
defaultDateColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'created_at' ||
context.column.columnId == 'updated_at'
? 'Before'
: 'After';
},
defaultArrayColumnFilter: 'NotIn',
},
},
initialState: {
Dashboard: {
ModuleButtons: ['ColumnFilter', 'SettingsPanel'],
PinnedToolbars: ['ColumnFilter'],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['Layout', 'ColumnFilter'],
},
],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'created_at',
'pushed_at',
'topics',
'updated_at',
'github_watchers',
'license',
'has_projects',
'has_pages',
'has_wiki',
'week_issue_change',
],
Name: 'Standard Layout',
ColumnSizing: {
name: {Width: 100},
language: {Width: 140},
github_stars: {Width: 130},
created_at: {Width: 160},
pushed_at: {Width: 160},
topics: {Width: 300},
updated_at: {Width: 160},
github_watchers: {Width: 130},
license: {Width: 100},
has_projects: {Width: 100},
has_pages: {Width: 100},
has_wiki: {Width: 100},
week_issue_change: {Width: 100},
},
},
],
},
},
};
```
### Default Text Predicate
Use the `defaultTextColumnFilter` property to set the default Predicate for text columns.
### `defaultTextColumnFilter`
Default Predicate to use for Text (string) Columns
Sets the Default Predicate to use for string / text Columns.
Options are: `Is`, `IsNot`, `Contains` (the default value), `NotContains`, `StartsWith`, `EndsWith`, `In`, `Regex`
This can be provided as a 'hard-coded' value:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultTextColumnFilter: 'StartsWith',
},
},
};
```
Or via a function which receives [`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md) and returns a Text Predicate:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultTextColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'language' ? 'In' : 'StartsWith';
},
},
},
};
```
### Default Numeric Predicate
Use the `defaultNumericColumnFilter` property to set the default Predicate for Numeric columns.
### `defaultNumericColumnFilter`
Default Predicate to use for Numeric Columns
Sets the Default Predicate to use for numeric Columns.
Options for this property are: `GreaterThan`, `LessThan`, `Equals` (the default value), `NotEquals`, `In`
This can be provided as a 'hard-coded' value:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultNumericColumnFilter: 'GreaterThan',
},
},
};
```
Or via a function which receives [`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md) and returns a Numeric Predicate:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultNumericColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'github_stars'
? 'GreaterThan'
: 'LessThan';
},
},
},
};
```
### Default Date Predicate
Use the `defaultDateColumnFilter` property to set the default Predicate for Date columns.
### `defaultDateColumnFilter`
Default Predicate to use for Date Columns
Sets the Default Predicate to use for date Columns.
Options are: `After`, `Before`, `On` (the default value), `NotOn`, `In`
This can be provided as a 'hard-coded' value:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultDateColumnFilter: 'After',
},
},
};
```
Or via a function which receives [`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md) and returns a Date Predicate:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultDateColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'created_at' ? 'Before' : 'After';
},
},
},
};
```
### Default Array Predicate
Use the `defaultArrayColumnFilter` property to set the default Predicate for Array (text and numeric) columns.
### `defaultArrayColumnFilter`
Default Predicate to use for Array-based Columns
Sets the Default Predicate to use for Array Columns (both string and numeric).
Options are: `In` (the default value), `NotIn`, `Blanks`, `NonBlanks`
This can be provided as a 'hard-coded' value:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultArrayColumnFilter: 'Blanks',
},
},
};
```
Or via a function which receives [`SystemPredicatesContext`](https://www.adaptabletools.com/docs/reference/systempredicatescontext.md) and returns an Array Predicate:
```ts {4}
const adaptableOptions: AdaptableOptions = {
filterOptions: {
columnFilterOptions = {
defaultArrayColumnFilter: (context: DefaultPredicateFilterContext) => {
return context.column.columnId == 'History' ? 'Blanks' : 'In';
},
},
},
};
```
---
# Column Filters Technical Reference
Canonical page: https://www.adaptabletools.com/docs/handbook-column-filter-technical-reference
- The Column Filter Applied Event fires whenever a Column Filter is applied in AdapTable
- Column Filter API Section of Adaptable API contains functions that manage AdapTable [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md)
- Column Filter Options provide many functions to run Column Filters
- AdapTable supplies a large number of System Predicates that can be used in Column Filters
## Column Filter State
There is no separate Column Filter State section in Initial Adaptable State.
Instead Column Filters are defined as a property of a [Layout](https://www.adaptabletools.com/docs/handbook-layouts/index.md) as part of [Layout Initial State](https://www.adaptabletools.com/docs/handbook-layouts-table-technical-reference/index.md).
--------------
## Filter Options
There are many filtering options in Filter Options section of AdapTable Options.
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [clearFiltersOnStartUp](https://www.adaptabletools.com/docs/reference/filteroptions.md#clearfiltersonstartup) | `boolean` | Clear Grid and Column Filters when AdapTable loads | false |
| [columnFilterOptions](https://www.adaptabletools.com/docs/reference/filteroptions.md#columnfilteroptions) | [`ColumnFilterOptions`](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md) | Options for managing Column Filters | |
| [customInFilterValues](https://www.adaptabletools.com/docs/reference/filteroptions.md#custominfiltervalues) | `(context: `[`CustomInFilterValuesContext`](https://www.adaptabletools.com/docs/reference/custominfiltervaluescontext.md)`) => Promise<`[`InFilterValueResult`](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md)`> \| `[`InFilterValueResult`](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md) | Provide custom values (or sorting / count info) when using `In` Predicate in Column or Grid Filter | |
| [enableFilterOnSpecialColumns](https://www.adaptabletools.com/docs/reference/filteroptions.md#enablefilteronspecialcolumns) | `boolean` | Allow filtering on Calculated & FreeText columns | true |
| [gridFilterOptions](https://www.adaptabletools.com/docs/reference/filteroptions.md#gridfilteroptions) | [`GridFilterOptions`](https://www.adaptabletools.com/docs/reference/gridfilteroptions.md) | Options for managing the Grid Filter | |
| [isRowFilterable](https://www.adaptabletools.com/docs/reference/filteroptions.md#isrowfilterable) | `(context: `[`IsRowFilterableContext`](https://www.adaptabletools.com/docs/reference/isrowfilterablecontext.md)`) => boolean` | Configures whether Rows will be evaluated when filtering | |
| [showDatePicker](https://www.adaptabletools.com/docs/reference/filteroptions.md#showdatepicker) | `boolean` | Show Date Picker (or Date Input) in Filter controls | true |
| [useAdaptableFiltering](https://www.adaptabletools.com/docs/reference/filteroptions.md#useadaptablefiltering) | `boolean` | Use Adaptable's Column & Grid Filters in preference to AG Grid's filtering | true |
### Column Filter Options
This includes a dedicated Column Filter Options section to enable full configuration of Column Filters.
| Property | Type | Description | Default |
| --- | --- | --- | --- |
| [defaultArrayColumnFilter](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#defaultarraycolumnfilter) | [`DefaultArrayColumnFilter`](https://www.adaptabletools.com/docs/reference/defaultarraycolumnfilter)` \| ((adaptableColumnContext: `[`DefaultPredicateFilterContext`](https://www.adaptabletools.com/docs/reference/defaultpredicatefiltercontext.md)`) => `[`DefaultArrayColumnFilter`](https://www.adaptabletools.com/docs/reference/defaultarraycolumnfilter)`)` | Default filter type for array Columns ('textArray', 'numberArray', etc.) | In |
| [defaultDateColumnFilter](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#defaultdatecolumnfilter) | [`DefaultDateColumnFilter`](https://www.adaptabletools.com/docs/reference/defaultdatecolumnfilter)` \| ((adaptableColumnContext: `[`DefaultPredicateFilterContext`](https://www.adaptabletools.com/docs/reference/defaultpredicatefiltercontext.md)`) => `[`DefaultDateColumnFilter`](https://www.adaptabletools.com/docs/reference/defaultdatecolumnfilter)`)` | Default filter type for date Columns | On |
| [defaultNumericColumnFilter](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#defaultnumericcolumnfilter) | [`DefaultNumericColumnFilter`](https://www.adaptabletools.com/docs/reference/defaultnumericcolumnfilter)` \| ((adaptableColumnContext: `[`DefaultPredicateFilterContext`](https://www.adaptabletools.com/docs/reference/defaultpredicatefiltercontext.md)`) => `[`DefaultNumericColumnFilter`](https://www.adaptabletools.com/docs/reference/defaultnumericcolumnfilter)`)` | Default filter type for numeric Columns | Equals |
| [defaultTextColumnFilter](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#defaulttextcolumnfilter) | [`DefaultTextColumnFilter`](https://www.adaptabletools.com/docs/reference/defaulttextcolumnfilter)` \| ((adaptableColumnContext: `[`DefaultPredicateFilterContext`](https://www.adaptabletools.com/docs/reference/defaultpredicatefiltercontext.md)`) => `[`DefaultTextColumnFilter`](https://www.adaptabletools.com/docs/reference/defaulttextcolumnfilter)`)` | Default filter type for text Columns | Contains |
| [hideQuickFilterDropdown](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#hidequickfilterdropdown) | `(adaptableColumnContext: `[`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md)`) => boolean` | Hides Dropdown in Quick Filter Bar for a given Column | undefined |
| [indicateFilteredColumns](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#indicatefilteredcolumns) | `boolean` | Make Column Header distinctive for filtered columns, helps users see currently filtered columns | true |
| [manuallyApplyColumnFilter](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#manuallyapplycolumnfilter) | `boolean \| ((context: `[`AdaptableColumnContext`](https://www.adaptabletools.com/docs/reference/adaptablecolumncontext.md)`) => boolean)` | Manually apply Column Filters; an Apply Filter button is displayed and Quick Filter is disabled | false |
| [quickFilterDebounce](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#quickfilterdebounce) | `number` | Time to wait (in ms) before Filter Bar reacts to new value | 250 |
| [quickFilterHeight](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#quickfilterheight) | `number` | Height of Quick Filter Bar (if not provided, AG Grid default is used) | null |
| [quickFilterWildcards](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#quickfilterwildcards) | `Record` | Shortcut keystrokes that activate a Quick Filter operator, keyed by the filter-type name (e.g. `{ GreaterThan: ['>'], In: ['#', '['] }`). | |
| [showQuickFilter](https://www.adaptabletools.com/docs/reference/columnfilteroptions.md#showquickfilter) | `boolean` | Display Quick Filter Bar between Column Header and Grid (provided its been setup) | true |
--------------
## Column Filter API
The Column Filter API section of AdapTable API / FilterAPI enables Column Filters to be accessed, created, edited, deleted, suspended and shared programmatically:
| Method | Returns | Description |
| --- | --- | --- |
| [addBlanksToInFilterValues(columnDistinctValues)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#addblankstoinfiltervalues) | [`InFilterValueInfo`](https://www.adaptabletools.com/docs/reference/infiltervalueinfo.md)`[]` | Adds the Blanks Predicate if any value is null, undefined or an empty string |
| [clearAndSetColumnFilters(columnFilters)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#clearandsetcolumnfilters) | `void` | Clears existing Column Filters and sets new ones |
| [clearColumnFilter(columnFilter)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#clearcolumnfilter) | `void` | Clears given Column Filter in the current Layout |
| [clearColumnFilterForColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#clearcolumnfilterforcolumn) | `void` | Clears Column Filter for given Column |
| [clearColumnFilters()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#clearcolumnfilters) | `void` | Clears all Column Filters in the Current Layout |
| [clearColumnFiltersForColumns(columns)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#clearcolumnfiltersforcolumns) | `void` | Clears Column Filters for given set of Columns |
| [columnFiltersToString(columnFilters)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#columnfilterstostring) | `string` | Retrieves descriptions of given Column Filters |
| [columnFilterToString(columnFilter)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#columnfiltertostring) | `string` | Retrieves description of given Column Filter |
| [getActiveColumnFilters()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getactivecolumnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[]` | Retrieves all active/no-suspended Column Filters in currently applied Layout |
| [getColumnFilterDefs()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getcolumnfilterdefs) | [`ColumnFilterDef`](https://www.adaptabletools.com/docs/reference/columnfilterdef.md)`[]` | Retrieves the Column Filter definitions for all available Column Filters |
| [getColumnFilterForColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getcolumnfilterforcolumn) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)` \| undefined` | Retrieves the Column Filter for the specified Column. |
| [getColumnFilters()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getcolumnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[]` | Retrieves all Column Filters in currently applied Layout |
| [getColumnFiltersForLayout(layoutName)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getcolumnfiltersforlayout) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[]` | Retrieves all Column Filters in a given Layout |
| [getFilterPredicateDefsForColumn(column)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getfilterpredicatedefsforcolumn) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[]` | Gets all Filter Predicates available for a given Column |
| [getFilterPredicateDefsForColumnId(columnId)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#getfilterpredicatedefsforcolumnid) | [`AdaptablePredicateDef`](https://www.adaptabletools.com/docs/reference/adaptablepredicatedef.md)`[] \| undefined` | Gets all Filter Predicates available for a given ColumnId |
| [hideColumnFilterMenu()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#hidecolumnfiltermenu) | `void` | Hides Column Filter Menu |
| [hideQuickFilterBar()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#hidequickfilterbar) | `void` | Hides Quick Filter bar |
| [isColumnFilterActive(columnFilter)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#iscolumnfilteractive) | `boolean` | Checks if a Column Filter is active (i.e. Predicate has no inputs or has inputs with values) |
| [isColumnFilterActiveForColumn(columnId)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#iscolumnfilteractiveforcolumn) | `boolean` | Checks if the given Coumn has an active Column Filter |
| [isQuickFilterAvailable()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#isquickfilteravailable) | `boolean` | Whether Quick Filter is available for use |
| [isQuickFilterVisible()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#isquickfiltervisible) | `boolean` | Whether Quick Filter Form is currently visible |
| [refreshAllFilterValues()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#refreshallfiltervalues) | `Promise>` | Refreshes (reloads) the filter values for ALL Columns (for `IN` Filter). |
| [refreshFilterValues(columnId)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#refreshfiltervalues) | `Promise<`[`InFilterValueResult`](https://www.adaptabletools.com/docs/reference/infiltervalueresult.md)`>` | Refresh(reload) the filter values for a given Column (for `IN` Filter). |
| [resetAllFilterValues()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#resetallfiltervalues) | `void` | Reset(clear cache) the filter values for ALL Columns (for `IN` Filter). |
| [resetFilterValues(columnId)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#resetfiltervalues) | `void` | Reset(clear cache) the filter values for a given Column (for `IN` Filter). |
| [setColumnFilters(columnFilters)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#setcolumnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[] \| null` | Sets Column Filters in current Layout; replaces filters for existing column, leaving other column filters in place |
| [showQuickFilterBar()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#showquickfilterbar) | `void` | Makes Quick Filter Bar appear |
| [suspendAllColumnFilters()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#suspendallcolumnfilters) | `void` | Suspends all Column Filters |
| [suspendColumnFilter(columnFilter)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#suspendcolumnfilter) | `void` | Suspends a Column Filter |
| [unSuspendAllColumnFilters()](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#unsuspendallcolumnfilters) | `void` | Unsuspend all Column Filters |
| [unSuspendColumnFilter(columnFilter)](https://www.adaptabletools.com/docs/reference/columnfilterapi.md#unsuspendcolumnfilter) | `void` | Unsuspend a Column Filter |
--------------
## Column Filter Applied Event
The Column Filter Applied Event is triggered whenever a [Column Filter](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) is applied in AdapTable.
This is often used when wanting to [evaluate expressions on the Server](https://www.adaptabletools.com/docs/adaptable-server-evaluation/index.md)
### ColumnFilterAppliedInfo
The Event's [`columnfilterappliedinfo`](https://www.adaptabletools.com/docs/reference/columnfilterappliedinfo.md) object contains a collection of currently applied Column Filters:
| Property | Type | Description |
| --- | --- | --- |
| [columnFilters](https://www.adaptabletools.com/docs/reference/columnfilterappliedinfo.md#columnfilters) | [`ColumnFilter`](https://www.adaptabletools.com/docs/reference/columnfilter.md)`[] \| undefined` | Currently applied Column Filters |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/columnfilterappliedinfo.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
### Event Subscription
Subscribing to the Event is done the same way as with all [Adaptable Events](https://www.adaptabletools.com/docs/technical-reference-adaptable-events/index.md):
```ts
api.eventApi.on('ColumnFilterApplied', (eventInfo: ColumnFilterAppliedInfo) => {
// do something with the info
});
```
--------------
## System Filter Predicates
AdapTable provides a large number of [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) - which are available for both developers and end users.
- Additionally, developers can include [Custom Predicate Definitions](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) to augment the System Filters
- Alternatively they can [override the default System Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md#overriding-system-predicates) with custom behavior as needed
Most System Predicates are available for use when creating [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md).
The full list (including the [Column Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) they operate on, and the number of Inputs they accept) is:
| Predicate | Column Data Type | Number of Inputs |
| ------------- | :--------------: | :--------------: |
| `Blanks` | (All) | 0 |
| `NonBlanks` | (All) | 0 |
| `In` | (All) | n |
| `NotIn` | (All) | n |
| `Equals` | `number` | 1 |
| `NotEquals` | `number` | 1 |
| `GreaterThan` | `number` | 1 |
| `LessThan` | `number` | 1 |
| `Positive` | `number` | 0 |
| `Negative` | `number` | 0 |
| `Zero` | `number` | 0 |
| `NotBetween` | `number` | 2 |
| `Is` | `text` | 1 |
| `IsNot` | `text` | 1 |
| `Contains` | `text` | 1 |
| `NotContains` | `text` | 1 |
| `StartsWith` | `text` | 1 |
| `EndsWith` | `text` | 1 |
| `Regex` | `text` | 1 |
| `Today` | `date` | 0 |
| `Yesterday` | `date` | 0 |
| `Tomorrow` | `date` | 0 |
| `ThisWeek` | `date` | 0 |
| `ThisMonth` | `date` | 0 |
| `ThisQuarter` | `date` | 0 |
| `ThisYear` | `date` | 0 |
| `InPast` | `date` | 0 |
| `InFuture` | `date` | 0 |
| `Before` | `date` | 1 |
| `After` | `date` | 1 |
| `On` | `date` | 1 |
| `NotOn` | `date` | 1 |
| `NextWorkDay` | `date` | 0 |
| `LastWorkDay` | `date` | 0 |
| `WorkDay` | `date` | 0 |
| `Holiday` | `date` | 0 |
| `Range` | `date` | 2 |
| `True` | `boolean` | 0 |
| `False` | `boolean` | 0 |
---
# Format Columns
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting
- The **Format Column** module controls how column values read and how cells look in AG Grid
- Each definition can include a [Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md), an [Style](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md), or both
- Definitions are scoped to columns, data types, or whole rows; an optional [Condition](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) limits when a rule applies
- Multiple Format Columns can apply to the same column; AdapTable resolves precedence automatically
The Format Column module lets users control how values read and how cells look in AG Grid.
- AdapTable also provides a comprehensive [Theming Module](https://www.adaptabletools.com/docs/handbook-theming/index.md)
- That is used to theme the AdapTable UI (i.e. all wizards and popups) rather than AG Grid Columns, Rows & Cells
Each Format Column definition shares the same building blocks:
- **Scope** — which columns, data types, or whole rows are in scope (see [Scope](#scope) below)
- **Target** — cell or column header
- **Display Format** and/or **Style** — how values read and how cells look (not mutually exclusive)
- **Condition** — optional rule; most often used with styles (see [Conditional Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md))
- **Row scope** — data rows, group rows, summaries, and related settings
- Format Columns apply to **all column types** including [Calculated](https://www.adaptabletools.com/docs/handbook-calculated-column/index.md) and [Free Text](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) columns
- Formatted columns remain editable and filterable when those features are enabled on the column
- [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md) — numeric, date, string, and custom value formatters (presets included)
- [Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) — colours, fonts, alignment, and optional CSS classes
- [Conditional Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) — predicate and expression rules (under Styles in the sidebar)
**Example: Column Formatting**
How Column Formatting Works
- This example contains a mixture of different Column Formats and Styles:
- `Name` has an Adaptable Style of Bold
- `Github Stars` has a Display Format (showing a Prefix) and Adaptable Style for both fore and back colours
- All `Date` columns have a Display Format of 'MMM do yyyy' applied
- A Blue Style has been set for the Whole Row, using a Condition: `[language] = "TypeScript" AND [license] = "MIT License"`
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Formatting Columns',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'FormatColumn',
Layouts: [
{
Name: 'FormatColumn',
TableColumns: [
'name',
'github_stars',
'has_projects',
'language',
'closed_issues_count',
'created_at',
'license',
'open_pr_count',
'updated_at',
'pushed_at',
'has_wiki',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Scope: {
ColumnIds: ['name'],
},
Style: {
FontWeight: 'Bold',
},
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
Style: {
ForeColor: '#c2bb00',
BackColor: '#f5f5f5',
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Prefix: 'Stars: ',
},
},
},
{
Name: 'formatColumn-date',
Scope: {
DataTypes: ['date'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy',
},
},
Style: {
Alignment: 'Center',
},
},
{
Name: 'style-all',
Style: {
BackColor: '#00ffff',
ForeColor: 'Black',
},
Scope: {
All: true,
},
Rule: {
BooleanExpression:
'[language] = "TypeScript" AND [license] = "MIT License" ',
},
},
],
},
},
};
```
The style specified in Column Formatting has the **lowest** level of precedence when AdapTable applies styling.
### Style Precedence in AdapTable
There are 3 Modules in AdapTable that can apply cell styling - so which takes precedence?
The answer is that the shorter the display time, and the less frequently the style is applied, the higher the precedence.
Which means that the order in which AdapTable will apply a Style to a cell is:
1. Any [Flashing Cells](https://www.adaptabletools.com/docs/handbook-flashing-cell/index.md)
2. A [Quick Search](https://www.adaptabletools.com/docs/handbook-quick-search/index.md)
3. Format Column
## Scope
Scope defines **where** the Format Column is applied.
Scope is provided by the commonly-used [Column Scope Object](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) which provides 4 sets of options:
- **All Columns** - The entire Row can be be rendered with a Format Column (by providing a Scope of 'All')
- **Columns** - consists of a list of Column Names which will display the Style
- **Column Types** - applies style to all Columns share supplied [Column Type](https://www.adaptabletools.com/docs/dev-guide-columns-column-types/index.md)
- **Data Types** - applies style to all Columns which share supplied [Cell Data Type](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-data-types/index.md) (e.g. `text`, `number` or `date`)
Use this to give all dates a distinctive format, or apply a condition to all numbers, e.g. Green Positive / Red Negative
**Example: Format Column - Scope**
Column Scope in Format Columns
- This demo showcases how to use Scope in Format Columns
- The `Issue Change` **Column** has 2 Format Conditions applied (Green for Positive and Red for Negative)
- All Columns of **DataType** `Date` have a Display Format (of 'MMM do yyyy')
- Columns with a **ColumnType** of 'Github' (i.e. `Github Watchers` & `Github Stars`) are italicised and centre-aligned
- **Whole Rows** are styled with match an Expression ('[language] = "TypeScript" AND [license] = "MIT License" ')
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Scope',
columnOptions: {
columnTypes: ['github', 'issue-pr'],
},
initialState: {
Dashboard: {ModuleButtons: ['FormatColumn', 'SettingsPanel']},
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
// Column Scope
{
Name: 'formatColumn-week_issue_change',
Style: {
ForeColor: 'Green',
},
Scope: {
ColumnIds: ['week_issue_change'],
},
Rule: {
Predicates: [
{
PredicateId: 'Positive',
},
],
},
},
{
Name: 'formatColumn-week_issue_change',
Style: {
ForeColor: 'Red',
},
Scope: {
ColumnIds: ['week_issue_change'],
},
Rule: {
Predicates: [
{
PredicateId: 'Negative',
},
],
},
},
// DataType Scope
{
Name: 'formatColumn-date',
Scope: {
DataTypes: ['date'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy',
},
},
},
// ColumnType Scope
{
Name: 'formatColumn-github',
Scope: {
ColumnTypes: ['github'],
},
Style: {
FontStyle: 'Italic',
Alignment: 'Center',
},
},
// Row Scope
{
Name: 'style-all',
Style: {
BackColor: '#8fd3fe',
ForeColor: 'Black',
},
Scope: {
All: true,
},
Rule: {
BooleanExpression:
'[language] = "TypeScript" AND [license] = "MIT License" ',
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
### Composition & Precedence
Each Column will render **every** Format Column for which it is in Scope.
This means that a Column can successfully display 2 (or more) Format Columns.
If a Column is in scope for 2 clashing Format Columns, AdapTable renders the Format Column with **higher precedence**
See [Configuring Formatting](https://www.adaptabletools.com/docs/handbook-column-formatting-configuring/index.md) for further details on composition and precedence
## Condition
By default, a Format Column applies to every cell in scope. An optional **Rule** limits application to matching rows — commonly for conditional highlighting (e.g. negative P&L, limit breaches). The same Rule mechanism can also gate a Display Format, though that is less common.
See [Conditional Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) for predicates, expressions, and demos
---
## Using Column Formats
Run-time users are able to add, edit, share, suspend and delete Format Columns using the relevant section in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md).
There are not [Toolbars](https://www.adaptabletools.com/docs/ui-dashboard-tabs-toolbars/index.md) or [Tool Panels](https://www.adaptabletools.com/docs/ui-tool-panel/index.md) for Format Columns
A Menu Item in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) opens the relevant Wizard.
- When Creating Format Columns the `Create Format Column` menu item appears in every [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md)
- When Editing each existing Format Column has an `Edit Format Column` Column Menu Item
The Format Column Wizard enables creating and editing Format Columns.
### Using the Format Column Wizard
There are many stages when creating a Column Style or Display Format in the AdapTable Wizard:
Choose a name for the Format Column being created.
Specify which rows should be included in the Column Format. Options are:
- Data Rows
- Group Rows
- Row Summaries
This defines where the Format Column style is applied. Options are:
- one (or more) **Columns**
- one (or more) **DataTypes** (e.g. String, Number, Date etc)
- an entire **Row** (Scope of 'All')
See [Guide to Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) for more information on this commonly used object
This sets which elements of the Format Column are styled. Options are:
- **Cell** (default)
- **Column Header**
Column Headers cannot use Conditions or Display Formats - only Styles
Provide a Condition which states whether or not the Format will be applied.
There are 3 possibilities:
- No Condition - the Format will always be applied
- A Predicate - Format is applied according to [Predicate](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) evaluation
- An Expression - Format is applied based on an [Expressios](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) which is evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md)
Read more about [Predicates](https://www.adaptabletools.com/docs/adaptable-predicate/index.md) and [Expressios](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) in the AdapTableQL Guide
Use the Style Component to create an Adaptable Style for the column.
You can specify:
- Fore, Back and Border Colours
- Font Properties: Bold, Italic, Size etc
- Cell Alignment for the Column - Left, Right or Centre
Use this Step if you wish to set a Display Format for the Column.
The available properties differ based on the Column's DataType:
- String - Select from the String properties and / or add a Prefix or Suffix
- Number - Create a Display Format by filling in the form, or select one of the Numeric presets
- Date - Provide a 'Date' pattern (using a [symbol](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)) or apply one of the Date presets
Display Formatting is only available if all the Columns in the Scope are all Numeric, all String or all Date
## AG Grid Rendering
AG Grid provides very powerful, custom column display functionality, using a combination of [Value Getters](https://www.ag-grid.com/javascript-data-grid/value-getters/), [Value Formatters](https://www.ag-grid.com/javascript-data-grid/value-formatters/) and [Cell Components](https://www.ag-grid.com/javascript-data-grid/cell-rendering/) (previously called Cell Renderers)
All of these will work in AdapTable and nothing will be lost.
However despite the richness of the AG Grid rendering capabilities we recommend **not using AG Grid's Value Formatters or Cell Components**, if possible, and instead to use AdapTable's Styling and Formatting features.
See the [Tutorial on AG Grid Cell Rendering](https://www.adaptabletools.com/docs/dev-guide-aggrid-cell-rendering/index.md) for more information and examples
## UI Entitlements
The UI Entitlements behaviour for Format Columns is as expected for `Full` and `Hidden` [`Access Levels`](https://www.adaptabletools.com/docs/reference/accesslevel.md).
The `ReadOnly` Entitlement behaviour is that the Columns will still be rendered but Users are not permitted to manage or suspend the Format Column definitions.
---
# Applying AdapTable Style
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style
- Format Columns can be given an AdapTable Style
- Styles can be either always rendered or when a Condition is met
- Styles consist of 2 types of properties:
- Colours - for Text, Cell Background and Border
- Font - Size, Style, Weight
- There is also an option to use supplied CSS Classes if required
Format Columns in AdapTable can be provided with a Style which is used when the column is rendered.
This style can be one of 2 types:
- an **AdapTable Style** object
- a **CSS Style**
Use [Conditional Styling](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) when the style should apply only when a particular rule is met
## AdapTable Style
The most basic type of Format Column uses an [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md).
This will render all Scoped Cells in the Format Column (or those which meet the Condition, if one is set).
The Style defines fore, back and border colours and a selection of font-related and alignment properties:
| Property | Type | Description |
| --- | --- | --- |
| [ClassName](https://www.adaptabletools.com/docs/reference/adaptablestyle.md#classname) | `string` | Existing CSS Class; use instead of setting other object properties |
The [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) is used in a number of places in AdapTable where styling is required
**Example: Column Formatting: Column Styles**
Column Formatting using Adaptable Styles
- This example has 3 Format Columns provided which display a Column Style:
- `Name` column is bold
- `Language` column has a blue background and yellow text color (and a Cell Alignment of Center)
- all `Number` columns are italic
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Column Formats with Column Style',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'language',
'closed_issues_count',
'open_pr_count',
'closed_pr_count',
],
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Scope: {
ColumnIds: ['name'],
},
Style: {
FontWeight: 'Bold',
},
},
{
Name: 'formatColumn-language',
Scope: {
ColumnIds: ['language'],
},
Style: {
BackColor: '#2966a8',
ForeColor: 'yellow',
Alignment: 'Center',
},
},
{
Name: 'formatColumn-number',
Scope: {
DataTypes: ['number'],
},
Style: {
FontStyle: 'Italic',
},
},
],
},
},
};
```
## CSS Style
It is possible to apply **existing** CSS styles to the cell instead of defining the styles individually.
This is done by specifying the property `ClassName` which references a defined CSS class
See [Setting CSS Style for Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md#cssclass-option) for more information
**Example: Column Formatting: CSS Classes**
Format Column with an external CSS Class
- This demo showcases applying external CSS classes to Format Columns:
- all numeric columns show the `rednumber` CSS class
- the `Language` and `License` columns show the `bluetext` CSS class
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column using CSS ClassName',
userInterfaceOptions: {
styleClassNames: ['rednumber', 'bluetext'],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-number',
Style: {
ClassName: 'rednumber',
},
Scope: {
DataTypes: ['number'],
},
},
{
Name: 'formatColumn-language',
Style: {
ClassName: 'bluetext',
},
Scope: {
ColumnIds: ['language', 'license'],
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
```css
.rednumber {
text-align: right !important;
color: red !important;
font-weight: bolder !important;
}
.bluetext {
text-align: center !important;
color: lightblue !important;
font-style: italic !important;
}
```
---
# Conditional Styling
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-conditions
- Optional **Rules** on Format Column definitions — apply a style or display format only when a cell or row matches
- Scoped to specific columns or whole rows
- Rule types: [Predicate](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions-predicates/index.md) or [Expression](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions-expressions/index.md) (AdapTableQL)
This section sits under [Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md) in the handbook — conditional rules are most often used to highlight cells, though the same `Rule` property can gate a Display Format when needed.
[Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) can be provided with a [`Rule`](https://www.adaptabletools.com/docs/reference/formatcolumn.md#rule) - which specifies whether or not to render the Format.
This allows users to create very visually striking Grids with a minimum of effort.
Conditions can be applied to both elements of Column Formatting:
- [Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md)
- [AdapTable Style](https://www.adaptabletools.com/docs/handbook-column-formatting-adaptable-style/index.md)
The Rule can be either of the two types of evaluation which AdapTableQL supports:
- Predicate(s) - either System or Custom
- a Boolean Expression
- Both Predicates and Boolean Expressions are evaluated using AdapTableQL
- Expressions are more powerful as they can contain multiple criteria and AND / OR logic
Conditions are evaluated in Real Time so Format Columns are applied automatically as Grid data updates.
- Format Columns with Conditions are only applied when the cell values satisfy all supplied criteria
- e.g. All **Predicate** rules (if they are provided), or **all the criteria in the Expression** (if that is being used) must be true
**Example: Format Column - Conditions**
Conditional Rules in Format Columns
- This example shows a Column Format containing Conditions based on Predicates and Expressions
- 2 **Predicates** on the `Issue Change` Column showing positive numbers as Green and negative numbers as Red
- **Expression** with Scope of `All` (i.e. Whole Row) and Style of Blue Background and Brown Font where `Language` is 'TypeScript' and `License` is 'MIT License'
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Conditions',
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-week_issue_change',
Style: {
ForeColor: 'Green',
},
Scope: {
ColumnIds: ['week_issue_change'],
},
Rule: {
Predicates: [
{
PredicateId: 'Positive',
},
],
},
},
{
Name: 'formatColumn-week_issue_change',
Style: {
ForeColor: 'Red',
},
Scope: {
ColumnIds: ['week_issue_change'],
},
Rule: {
Predicates: [
{
PredicateId: 'Negative',
},
],
},
},
{
Name: 'style-all',
Style: {
BackColor: '#8fd3fe',
ForeColor: 'Brown',
},
Scope: {
All: true,
},
Rule: {
BooleanExpression:
'[language] = "TypeScript" AND [license] = "MIT License" ',
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Conditional Styles using Expressions
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-conditions-expressions
- Format Column Conditions can use an Expression (instead of a Predicate)
- This is useful for more advanced scenarios or if AND / OR functionality is required
For more complicated scenarios there is an option to use an Expression.
This will be evaluated by [AdapTableQL](https://www.adaptabletools.com/docs/adaptable-ql-expression/index.md) (as with Calculated Columns, Alerts etc).
This is a Boolean [Expression](https://www.adaptabletools.com/docs/adaptable-ql-expression-standard/index.md) (as it has to evaluate to true / false)
The Expression can reference multiple columns and can contain `AND` and `OR` and more advanced logic.
If the Format Column's Scope is `All` (i.e. the whole Row) **the Rule must be an Expression** (rather than a Predicate)
**Example: Format Column - Expression Condition**
Expression Conditions in Format Columns
- This example shows a Column Format containing a style of Blue Background and Brown Font and a Scope of All
- An Expression is also provided stipulating the Style only applies in Rows where `Language` is 'TypeScript' and `License` is 'MIT License'
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Expression Condition',
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'style-all',
Style: {
BackColor: '#8fd3fe',
ForeColor: 'Brown',
},
Scope: {
All: true,
},
Rule: {
BooleanExpression:
'[language] = "TypeScript" AND [license] = "MIT License" ',
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
---
# Conditional Styles using Predicates
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-conditions-predicates
- Most Format Column Style Conditions use a Predicate
- This is evaluated by AdapTableQL - AdapTable's Query Language
- A Format Column Condition can contain multiple Predicates if required
- Conditions can use a Referenced Predicate - with different styled and evaluated Columns
Predicates are the most common use case for setting a Format Column Condition.
## Standard Predicate Conditions
Predicates are easy to use to AdapTable and can be created visually at run-time through a wizard.
Predicates are ideal when the evaluation requires a single column or a single operation.
For example Price is `Positive`, Country is `NonBlank`, Amount is `GreaterThan` 20 etc.
See full explanations of how Predicates work in AdapTable in the [AdapTableQL Predicates Guide](https://www.adaptabletools.com/docs/adaptable-predicate/index.md)
**Example: Format Column - Predicate Condition**
Predicate Conditions in Format Columns
- This demo shows 3 Format Columns using Conditions with Predicates:
- `Issue Change` Column displays green font where value is `positive`
- `Issue Change` Column displays red font where value is `negative`
- Any string column will show as Bold and Upper case if the value includes '.js'
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Predicate Condition',
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-week_issue_change',
Style: {
ForeColor: 'Green',
},
Scope: {
ColumnIds: ['week_issue_change'],
},
Rule: {
Predicates: [
{
PredicateId: 'Positive',
},
],
},
},
{
Name: 'formatColumn-week_issue_change',
Style: {
ForeColor: 'Red',
},
Scope: {
ColumnIds: ['week_issue_change'],
},
Rule: {
Predicates: [
{
PredicateId: 'Negative',
},
],
},
},
{
Name: 'formatColumn-text',
Scope: {
DataTypes: ['text'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
Style: {
FontWeight: 'Bold',
},
Rule: {
Predicates: [
{
PredicateId: 'Contains',
Inputs: ['js'],
},
],
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Multiple Predicate Conditions
Prior to [Version 14](https://www.adaptabletools.com/support/version-14-release-note) only a single Predicate could be supplied for each Format Column Condition.
There is now no limit on how many Predicates can be provided in each AlertRule.
This allows for a more powerful and flexibile rules to be set.
It allows users to use Predicates in preference to more complicated (and sometimes off-putting) Expressions
**Example: Format Column - Multiple Predicate Conditions**
Multiple Predicate Conditions in Format Columns
- This demo shows a Format Column Condition (Bold and Upper) with Multiple Predicates:
- the `Contains` predicate with an input of "js"
- the `NotIn` predicate with an input of "cyclejs"
### Expand to see the Format Column Definition with Multiple Predicates
```ts
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-text-116',
Scope: {
DataTypes: ['text'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
Style: {
FontWeight: 'Bold',
},
Rule: {
Predicates: [
{
PredicateId: 'Contains',
Inputs: ['js'],
},
{
PredicateId: 'NotIn',
Inputs: ['cyclejs'],
},
],
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Multiple Predicate Conditions',
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-text',
Scope: {
DataTypes: ['text'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
Style: {
FontWeight: 'Bold',
},
Rule: {
Predicates: [
{
PredicateId: 'Contains',
Inputs: ['js'],
},
{
PredicateId: 'ExcludeValues',
Inputs: ['cyclejs'],
},
],
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'language',
'week_issue_change',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Referenced Predicate Conditions
Typically the Column defined in the Scope will be the one that is evaluated by the Predicate.
However this can be changed so there are separate Scopes for Column and Predicate.
This allows you, for example, to bold ColumnA values when the data in ColumnB meets the Rule in the Predicate.
- This is useful if the column being evaluated is hidden or only accessible by scrolling, so a visible column is styled
- Or if you want to style the first column in the Row and pin it
This is achieved by:
- setting the Format Column Scope to be the Column which will be rendered
- adding a `ColumnId` to the Predicate defined in the Format Column which will be the column evaluated
This `ColumnId` property in the Predicate is optional; if not supplied, the Format Column Scope is used
**Example: Format Column - Referenced Predicate Conditions**
Referenced Predicate Conditions in Format Columns
- This example shows how to use a Referenced Predicate:
- the **Predicate Scope** is `Github Watchers` and the Rule is `GreaterThan` *3300*
- the **Format Column Scope** is `Name` (which is also pinned) and that Column displayed the Format Column Style
- Note: This could also have been achieved by using an Expression of `[github_watchers] > 3300` and the same Format Column Scope
### Expand to see the Format Column Definition with a Referenced Predicate
```ts
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-name-117',
Style: {
FontWeight: 'Bold',
BorderColor: 'Yellow',
},
Scope: {
ColumnIds: ['name'],
},
Rule: {
Predicates: [
{
ColumnId: 'github_watchers',
PredicateId: 'GreaterThan',
Inputs: [3300],
},
],
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Referenced Predicates',
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Style: {
FontWeight: 'Bold',
BorderColor: 'Yellow',
},
Scope: {
ColumnIds: ['name'],
},
Rule: {
Predicates: [
{
ColumnId: 'github_watchers',
PredicateId: 'GreaterThan',
Inputs: [3300],
},
],
},
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
ColumnPinning: {
name: 'left',
},
TableColumns: [
'name',
'license',
'language',
'github_watchers',
'github_stars',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'week_issue_change',
'open_issues_count',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
],
AutoSizeColumns: true,
},
],
},
},
};
```
## Custom Predicate Conditions
Format Column Conditions can also use [Custom Predicates](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md).
These are bespoke Predicates defined by developers at design-time and then available for use in AdapTable.
**Example: Format Column: Custom Predicates**
Using Custom Predicates in Format Columns
- This demo creates 3 Custom Predicate Definitions and attaches a Format Column Condition to each:
- `Popular` on `Github Stars` Column with Format of Bold Font on Blue Background
- `Vanilla` on `Language` Column with Format of Yellow Font on Brown Background
- `Long String` on `Description` Column (using Input of 40) with Format of Italics and Purple Border
```ts
import {
AdaptableOptions,
PredicateDefHandlerContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Custom Predicates',
predicateOptions: {
customPredicateDefs: [
{
id: 'big_github',
label: 'Popular',
columnScope: {
ColumnIds: ['name'],
},
moduleScope: ['formatColumn'],
handler(params: PredicateDefHandlerContext) {
const githubStarsCount: number = params.node.data.github_stars;
const watchersCount: number = params.node.data.github_watchers;
return githubStarsCount > 50000 && watchersCount > 500 ? true : false;
},
},
{
id: 'vanilla',
label: 'Vanilla',
columnScope: {
ColumnIds: ['language'],
},
moduleScope: ['formatColumn'],
handler(params: PredicateDefHandlerContext) {
return params.value == 'JavaScript' || params.value == 'HTML';
},
},
{
id: 'long_string',
label: 'Long String',
columnScope: {DataTypes: ['text']},
moduleScope: ['formatColumn'],
handler(params: PredicateDefHandlerContext) {
if (params.inputs) {
const input = params.inputs[0];
return (params.value as String).length > input;
}
return false;
},
inputs: [{type: 'number'}],
toString: ({inputs}) => `cell length > ${inputs[0]}`,
},
],
},
initialState: {
Theme: {CurrentTheme: 'dark'},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-language',
Style: {
BackColor: 'Brown',
ForeColor: 'Yellow',
Alignment: 'Center',
},
Scope: {
ColumnIds: ['language'],
},
Rule: {
Predicates: [
{
PredicateId: 'vanilla',
},
],
},
},
{
Name: 'formatColumn-github_stars',
Style: {
BackColor: '#87cefa',
FontWeight: 'Bold',
},
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'big_github',
},
],
},
},
{
Name: 'formatColumn-description',
Style: {
FontStyle: 'Italic',
BorderColor: 'Purple',
},
Scope: {
ColumnIds: ['description'],
},
Rule: {
Predicates: [
{
PredicateId: 'long_string',
Inputs: [40],
},
],
},
},
],
},
StatusBar: {
StatusBars: [
{
Key: 'Center Panel',
StatusBarPanels: ['ColumnFilter'],
},
],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'language',
'name',
'github_stars',
'updated_at',
'description',
'pushed_at',
'github_watchers',
'open_issues_count',
'created_at',
'license',
],
AutoSizeColumns: true,
},
],
},
},
};
```
See [Guide to Creating Custom Predicates in AdapTableQL](https://www.adaptabletools.com/docs/adaptable-predicate-custom/index.md) for more information
---
# Configuring Column Formatting
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-configuring
- Developers provide Format Columns Styles, Display Formats and Conditions through Initial Adaptable State
- These include a property which stipulates whether the Format is applied in Grouped Rows
## Defining
Column Formatting can be provided at design-time through [Format Column Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
This will ensure that all styles and display formats are applied when the Application first loads, and that any changes will be stored with Adaptable State.
## Multiple Format Columns
It can be the case that several Format Column objects can all be scoped (i.e. be relevant) for the same grid cell.
When this happens all the Format Columns object are **composed** into a single Format Column.
AdapTable will merge all the Style properties into a single [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) object which will then be rendered.
- The order in which the Format Columns are defined - either in Initial Adaptable State or the UI - is important
- AdapTable has strict rules about **precedence** - see the section below for more information
**Example: Column Formatting Composition**
Merging multiple Format Columns together
- This example demonstrates how Format Columns are composed. We provide 4 Format Columns:
- **All** Columns are Centre Aligned
- **Numeric** Columns are Light Green
- 3 Columns - `Github Stars`, `Issue Change` and `Github Watchers` - are **Bold** and _Italic_
- The `Github Stars` Column has both a Prefix and a Suffix of '\*\*\*' but with [Condition](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) of > 20,000
- Note how each Columns display all the formats which are relevant to it, and the `Github Stars` column shows all 4 Formats
### Expand to see the Format Column Definitions
```
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-all-101',
Scope: {
All: true,
},
Style: {
Alignment: 'Center',
},
},
{
Name: 'FormatColumn-number-102',
Scope: {
DataTypes: ['number'],
},
Style: {
ForeColor: 'LightGreen',
},
},
{
Name: 'FormatColumn-github_stars-103',
Scope: {
ColumnIds: ['github_stars', 'week_issue_change', 'github_watchers'],
},
Style: {
FontWeight: 'Bold',
FontStyle: 'Italic'
},
},
{
Name: 'FormatColumn-github_stars-104',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Prefix: '***',
Suffix: '***',
},
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['20000'],
},
],
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Composition',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'week_issue_change',
'github_watchers',
'closed_issues_count',
'created_at',
'closed_pr_count',
'license',
'language',
'updated_at',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'style-all',
Scope: {
All: true,
},
Style: {
Alignment: 'Center',
},
},
{
Name: 'formatColumn-number',
Scope: {
DataTypes: ['number'],
},
Style: {
ForeColor: 'LightGreen',
},
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars', 'week_issue_change', 'github_watchers'],
},
Style: {
FontWeight: 'Bold',
FontStyle: 'Italic',
},
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Prefix: '***',
Suffix: '***',
},
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['20000'],
},
],
},
},
],
},
},
};
```
## Format Column Precedence
As noted above, multiple Format Columns are merged into a single [Adaptable Style](https://www.adaptabletools.com/docs/ui-tutorial-providing-adaptable-style/index.md) object.
However its important to note that Format Columns are evaluated in their **precedence order**.
This means that if several Format Columns define the **same** style property (e.g. background color, font size, etc.), the Format Column with the highest precedence wins.
Overlapping **Display Formats are NOT merged** - the one with the higher Precedence is displayed
AdapTable sets precedence purely on the **order** of the definitions in the [Format Column Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md).
Each element listed in the State has higher precedence than the next.
Precedence Rules are used not just for Styles and Display Format but also General Settings (e.g. Cell Alignment)
The Precedence order can be **changed at runtime** in 2 ways:
- using the UI buttons (up & down arrows) in the Format Column Setttings Panel
- programmatically using the [`increment`](https://www.adaptabletools.com/docs/reference/formatcolumnapi.md#incrementformatcolumnprecedence) & [`decrement`](https://www.adaptabletools.com/docs/reference/formatcolumnapi.md#decrementformatcolumnprecedence) API methods in Format Column API
- It is important that Format Columns with more specific conditions have a higher priority order
- Otherwise they would be overridden by more general Format Columns
**Example: Column Formatting Precedence Order**
Multiple Format Columns are merged according to Precedence
- This (slightly contrived) example provides 4 Display Format with various **different** and **overlapping** Scopes, Styles and DisplayFormats:
1. for `all numeric` columns with values greater than 1 million are divided by 1.000.000 and suffixed with 'M'
2. for `all numeric` columns with values greater than 1 thousand are divided by 1.000 and suffixed with 'K'
3. columns `github_stars`,`open_issues_count`,`open_pr_count` are displayed with a custom background color
4. all columns with the condition that the `license` is NOT 'MIT' are displayed with custom background, foreground, border and font style
**Note:** their definition (and implicitly precedence) order is determinant for the final formatting
- Increment/decrement the precedence order of each Format Column and check how the resulting formatting changes
- Suspend one or several Format Columns and check the resulting formatting
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Format Column Precedence',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'license',
'github_stars',
'closed_issues_count',
'created_at',
'closed_pr_count',
'updated_at',
'week_issue_change',
'github_watchers',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-number',
Scope: {
DataTypes: ['number'],
},
Style: {
BackColor: '#ffffe0',
FontWeight: 'Bold',
ForeColor: 'Purple',
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Suffix: 'M',
Multiplier: 0.000001,
},
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['1000000'],
},
],
},
},
{
Name: 'formatColumn-number',
Scope: {
DataTypes: ['number'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Suffix: 'K',
Multiplier: 0.001,
},
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: ['1000'],
},
],
},
},
{
Name: 'formatColumn-open_pr_count',
Scope: {
ColumnIds: ['open_pr_count', 'github_stars', 'open_issues_count'],
},
Style: {
BackColor: '#c2eef5',
ForeColor: 'Red',
},
},
{
Name: 'style-all',
Scope: {
All: true,
},
Style: {
BackColor: '#a8ffe5',
ForeColor: '#b10202',
BorderColor: '#f24040',
FontStyle: 'Italic',
},
Rule: {
BooleanExpression: `[license] != 'MIT License'`,
},
},
],
},
},
};
```
```ts
export const rowData = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 8794429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78548,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 7912435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 539735,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 938,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 97952,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 118049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date('2021-12-19T21:06:01').toDateString(),
homepage: 'https://solidjs.com',
github_stars: 819,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 23,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 130164,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 278940,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 106122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date('2021-12-20T00:37:09').toDateString(),
homepage: 'https://redwoodjs.com',
github_stars: 103334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 26316966,
name: 'cyclejs',
full_name: 'cyclejs/cyclejs',
html_url: 'https://github.com/cyclejs/cyclejs',
description:
'A functional and reactive JavaScript framework for predictable code',
created_at: new Date('2014-11-07T11:28:45').toDateString(),
updated_at: new Date('2021-12-20T06:39:49').toDateString(),
pushed_at: new Date('2021-12-17T11:03:37').toDateString(),
homepage: 'http://cycle.js.org',
github_stars: 99499,
language: 'TypeScript',
forks_count: 421,
open_issues_count: 102,
license: 'MIT License',
topics: [
'cyclejs',
'framework',
'functional-programming',
'hacktoberfest',
'javascript',
'reactive-programming',
'rxjs',
'typescript',
],
github_watchers: 205,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 563,
open_pr_count: 26,
closed_pr_count: 301,
week_issue_change: -2,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: new Date('2021-12-20T09:02:15').toDateString(),
pushed_at: new Date('2021-12-17T23:21:58').toDateString(),
homepage: 'https://preactjs.com',
github_stars: 3025538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date('2021-12-17T20:09:25').toDateString(),
homepage: 'https://riot.js.org',
github_stars: 145997,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 121594173,
name: 'aurelia',
full_name: 'aurelia/aurelia',
html_url: 'https://github.com/aurelia/aurelia',
description:
'Aurelia 2, a standards-based, front-end framework designed for high-performing, ambitious applications.',
created_at: new Date('2018-02-15T05:22:58').toDateString(),
updated_at: new Date('2021-12-19T04:23:43').toDateString(),
pushed_at: new Date('2021-11-28T16:21:43').toDateString(),
homepage: '',
github_stars: 987,
language: 'TypeScript',
forks_count: 121,
open_issues_count: 143,
license: 'MIT License',
topics: [
'aurelia',
'cordova',
'cross-platform',
'electron',
'framework',
'frontend',
'html',
'javascript',
'javascript-framework',
'mobile',
'pwa',
'single-page-applications',
'spa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 66,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 214,
open_pr_count: 17,
closed_pr_count: 959,
week_issue_change: 32,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date('2021-12-20T08:21:58').toDateString(),
homepage: 'https://nextjs.org',
github_stars: 7884046,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date('2021-12-20T08:05:15').toDateString(),
homepage: 'https://nuxtjs.org',
github_stars: 389997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 210095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
## Excluding Certain Rows
By default Column Formatting is automatically applied to **all Rows** - including Grouped, Summary and Total Rows.
The Format Column is only applied in Grouped and Total Rows to Columns which have an Aggregation set
This behaviour can be changed by configuring the `RowScope` property when defining the Format Column.
The [`RowScope`](https://www.adaptabletools.com/docs/reference/rowscope.md) object enables 4 types of rows to be **excluded** from the Format Column:
- Data Rows
- Grouped Rows
- Summary Rows
- Grand Total Rows
Use the `ExcludeDataRows` option to create a Format Column that is **only** rendered in a Group Row
**Example: Column Formatting - Excluding Rows**
Applying Formats only in Grouped Rows
- This Example has 3 Format Columns - with different configurations for Grouped Rows and Data Rows:
- `Github Stars` has a Style (with fore and back colours and italicised) - with Grouped Rows **excluded**
- `Closed Issues` is Blue and has a Cell Alignment of `Center` - with Grouped Rows **included**
- `Open PRs` is Bold and yellow - with Grouped Rows **included** but Data Rows **excluded**
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Formatting Grouped Rows',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'github_stars',
'closed_issues_count',
'open_pr_count',
'created_at',
'license',
'updated_at',
'pushed_at',
'has_projects',
'has_wiki',
],
RowGroupedColumns: ['language'],
TableAggregationColumns: [
{
ColumnId: 'closed_issues_count',
AggFunc: 'max',
},
{
ColumnId: 'github_stars',
AggFunc: 'sum',
},
{
ColumnId: 'open_pr_count',
AggFunc: 'avg',
},
],
RowGroupValues: {
RowGroupDefaultBehavior: 'collapsed',
GroupKeys: [
{
RowGroupedColumns: ['language'],
ExceptionGroupKeys: [['HTML']],
},
],
},
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
Style: {
ForeColor: '#c2bb00',
BackColor: '#f5f5f5',
FontStyle: 'Italic',
},
RowScope: {
ExcludeGroupRows: true,
},
},
{
Name: 'formatColumn-closed_issues_count',
Scope: {
ColumnIds: ['closed_issues_count'],
},
Style: {
ForeColor: 'LightBlue',
Alignment: 'Center',
},
},
{
Name: 'formatColumn-open_pr_count',
Scope: {
ColumnIds: ['open_pr_count'],
},
Style: {
ForeColor: 'Yellow',
FontWeight: 'Bold',
},
RowScope: {
ExcludeDataRows: true,
},
},
],
},
},
};
```
## Excluding Column Groups
By default Column Formatting is automatically to Columns which are inside [Column Groups](https://www.adaptabletools.com/docs/handbook-grouping-columns/index.md).
However it is possible to apply the formatting only if the containing Column Group is expanded or collapsed.
This is done using the `ColumnGroupScope` property in the Format Column object which can take 3 values:
- `Both` (the default)
- `Expanded`
- `Collapsed`
See [Formatting Column Groups](https://www.adaptabletools.com/docs/handbook-grouping-columns-formatting/index.md) for more details and a demo
---
# Display Format
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-display-format
- Display Formats are used to format the text displayed in Cells
- AdapTable provides a number of System Display Format Options that can be configured for:
- Numeric columns (with named presets or full formatter options)
- Date columns (with pattern-based formats and wizard presets)
- String columns
- Additionally developers can provide their own Custom Display Formats
- Conditions can be added so that only cells with meet the Rule are formatted
- AdapTable also provides Presets (for Numeric and Date columns) as a convenience feature
Format Columns can be provided with a Display Format.
This defines how the value in each cell in the column is formatted.
Provide a [Column Formatting Condition](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) if you want the Display Format only to apply when a rule is met
Setting a Display Format does **not** change the underlying cell value
AdapTable provides 3 sets of System Display Formats, based on the data type of the Column:
- [Numeric Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md)
- [String Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-string/index.md)
- [Date Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-date/index.md)
AdapTable also provides Numeric and Date presets for commonly-added Formats
In addition developers can provide [Custom Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-custom/index.md) if the System Display Formats are insufficient.
When a Display Format is applied, any [Column Filters](https://www.adaptabletools.com/docs/handbook-column-filter/index.md) will be evaluated on the column's **underlying** (i.e. raw) value
## Defining Display Formats
Display Formats are defined on [Format Columns](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md) in `initialState.FormatColumn.FormatColumns`.
Each entry needs a `Name`, a [Column Scope](https://www.adaptabletools.com/docs/dev-guide-columns-scope/index.md) (`Scope`), and a `DisplayFormat` — either a formatter object or (numeric columns only) a preset name.
### Providing Display Formats in Initial State
Create one or more objects under `FormatColumn.FormatColumns`. Each targets columns via `Scope` and sets how cell text is rendered.
Each Format Column object needs a unique Name
It also needs Scope defined - **where** it is applied
Provide `DisplayFormat` to tell AdapTable to create a format rather than a Style
Use `Formatter: 'StringFormatter'` and `Options` (e.g. `Case`, `Prefix` or `Trim`).
Here `name` is shown in uppercase.
There are no presets available for String Columns.
Use `Formatter: 'DateFormatter'` with `Options.Pattern` (Unicode date field symbols).
Here `created_at` uses `yyyy/MM/dd`.
There are no configuration presets available for Date Columns.
For common numeric layouts, you can set `DisplayFormat` to a preset name (e.g. `'Accounting'`).
AdapTable resolves it to a `NumberFormatter` at runtime.
Here `week_issue_change` shows negatives in parentheses (`Accounting` preset).
When no preset fits, supply the full object: `Formatter: 'NumberFormatter'` and the options you need (`Multiplier`, `Suffix`, `FractionDigits`, etc.).
Here `github_stars` is scaled to thousands with a `K` suffix — not the same as the `'Thousand'` preset (different fraction digits).
```js [[1, 2, "FormatColumn"], [1, 3, "FormatColumns"], [2, 5, "Name"], [2, 6, "Scope"], [3, 9, "DisplayFormat"], [4, 10, "StringFormatter"], [4, 11, "Options"], [4, 12, "Case"], [2, 17, "Name"], [2, 18, "Scope"], [3, 21, "DisplayFormat"], [5, 22, "DateFormatter"], [5, 23, "Options"], [5, 24, "Pattern"], [2, 29, "Name"], [2, 30, "Scope"], [3, 33, "DisplayFormat"],[6, 33, "Accounting"], [2, 36, "Name"], [2, 37, "Scope"], [3, 40, "DisplayFormat"], [7, 41, "NumberFormatter"], [7, 42, "Options"], [7, 43, "FractionDigits"], [7, 44, "Multiplier"], [7, 45, "Suffix"]]
const initialState: InitialState = {
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Scope: {
ColumnIds: ['name'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
},
{
Name: 'formatColumn-created_at',
Scope: {
ColumnIds: ['created_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'yyyy/MM/dd',
},
},
},
{
Name: 'formatColumn-week_issue_change',
Scope: {
ColumnIds: ['week_issue_change'],
},
DisplayFormat: 'Accounting',
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 1,
Multiplier: 0.001,
Suffix: 'K',
},
},
},
],
},
};
```
**Example: Column Formatting: Display Formats**
Column Formatting with Display Formats
- This example shows four Display Formats (see [Defining Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format/index.md#defining-display-formats) above):
- `Name` — string (`Case: 'Upper'`)
- `Created` — date (`Pattern: 'yyyy/MM/dd'`)
- `Issue Change` — numeric preset (`'Accounting'`)
- `Github Stars` — numeric options (`Multiplier` + `K` suffix)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Display Formats',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'created_at',
'week_issue_change',
'github_stars',
'closed_pr_count',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Scope: {
ColumnIds: ['name'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
},
{
Name: 'formatColumn-created_at',
Scope: {
ColumnIds: ['created_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'yyyy/MM/dd',
},
},
},
{
Name: 'formatColumn-week_issue_change',
Scope: {
ColumnIds: ['week_issue_change'],
},
DisplayFormat: 'Accounting',
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 1,
Multiplier: 0.001,
Suffix: 'K',
},
},
},
],
},
},
};
```
## Display Format Presets
AdapTable provides **presets** for numeric and date columns.
For Date columns, presets is a purely UI convenience feature allowing run-time users to quickly apply the datetime pattern they require in the UI wizard.
For Numeric columns, presets can be used in 2 ways:
- as a convenience feature for run-time users to quickly apply a display format (similar to dates)
- as a configuration option for developers who can reference the preset by name when defining the object
See [Using Date Presets](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-date/index.md#date-presets) and [Using Numeric Presets](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md#numeric-presets) for more information
## Display Format Precedence
Display Formats follow the same rules as general [Column Formatting Precedence](https://www.adaptabletools.com/docs/handbook-column-formatting/index.md#precedence-of-format-columns).
Namely, the Display Formats are evaluated in the order they are provided in Initial Adaptable State or the UI.
This allows you create multiple display formats for the same column which will be evaluated in the order provided
**Example: Column Formatting: Format Precedence**
Column Formatting with a multiply Display Formats
- In this demo we provide 2 Display Formats - each with a Condition - both on the `Github Stars` Column:
- Any cells > 1,000,000 will display as xM
- Any cells > 1,000 will display as xK
- Any cells under 1000 will display normally
- **Note**: We need to put the 'Million' condition first, as otherwise only the Thousand condition will display
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Display Formats Precedence',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'created_at',
'updated_at',
'week_issue_change',
'closed_pr_count',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [1000000],
},
],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Multiplier: 0.000001,
Suffix: 'M',
FractionDigits: 2,
},
},
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
Rule: {
Predicates: [
{
PredicateId: 'GreaterThan',
Inputs: [1000],
},
],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Multiplier: 0.001,
Suffix: 'K',
FractionDigits: 2,
},
},
},
],
},
},
};
```
```ts
export const rowData = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 8794429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78548,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 7912435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: -9,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 539735,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 938,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 21,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 97952,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 118049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 12,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date('2021-12-19T21:06:01').toDateString(),
homepage: 'https://solidjs.com',
github_stars: 819,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 23,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 130164,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 278940,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: -14,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 106122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date('2021-12-20T00:37:09').toDateString(),
homepage: 'https://redwoodjs.com',
github_stars: 103334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 26316966,
name: 'cyclejs',
full_name: 'cyclejs/cyclejs',
html_url: 'https://github.com/cyclejs/cyclejs',
description:
'A functional and reactive JavaScript framework for predictable code',
created_at: new Date('2014-11-07T11:28:45').toDateString(),
updated_at: new Date('2021-12-20T06:39:49').toDateString(),
pushed_at: new Date('2021-12-17T11:03:37').toDateString(),
homepage: 'http://cycle.js.org',
github_stars: 99499,
language: 'TypeScript',
forks_count: 421,
open_issues_count: 102,
license: 'MIT License',
topics: [
'cyclejs',
'framework',
'functional-programming',
'hacktoberfest',
'javascript',
'reactive-programming',
'rxjs',
'typescript',
],
github_watchers: 205,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 563,
open_pr_count: 26,
closed_pr_count: 301,
week_issue_change: -2,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: new Date('2021-12-20T09:02:15').toDateString(),
pushed_at: new Date('2021-12-17T23:21:58').toDateString(),
homepage: 'https://preactjs.com',
github_stars: 3025538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date('2021-12-17T20:09:25').toDateString(),
homepage: 'https://riot.js.org',
github_stars: 145997,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 121594173,
name: 'aurelia',
full_name: 'aurelia/aurelia',
html_url: 'https://github.com/aurelia/aurelia',
description:
'Aurelia 2, a standards-based, front-end framework designed for high-performing, ambitious applications.',
created_at: new Date('2018-02-15T05:22:58').toDateString(),
updated_at: new Date('2021-12-19T04:23:43').toDateString(),
pushed_at: new Date('2021-11-28T16:21:43').toDateString(),
homepage: '',
github_stars: 987,
language: 'TypeScript',
forks_count: 121,
open_issues_count: 143,
license: 'MIT License',
topics: [
'aurelia',
'cordova',
'cross-platform',
'electron',
'framework',
'frontend',
'html',
'javascript',
'javascript-framework',
'mobile',
'pwa',
'single-page-applications',
'spa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 66,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 214,
open_pr_count: 17,
closed_pr_count: 959,
week_issue_change: 32,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date('2021-12-20T08:21:58').toDateString(),
homepage: 'https://nextjs.org',
github_stars: 7884046,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date('2021-12-20T08:05:15').toDateString(),
homepage: 'https://nuxtjs.org',
github_stars: 389997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 210095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
### How AdapTable applies Display Formats
Display Formats are a **presentation layer**.
They change the text AG Grid renders in a cell; the value held on the row (and used for most filter logic) stays the same.
AG Grid Integration
When a column has one or more active Format Columns with `DisplayFormat` set, AdapTable wires AG Grid’s `valueFormatter` on that column’s `ColDef`.
- AdapTable does **not** create a separate AG Grid formatter per Format Column
- There is **one** `valueFormatter` on the column; it delegates to AdapTable for each cell
If no Format Column with `DisplayFormat` applies to that column, any `valueFormatter` you supplied in your own `columnDefs` is left unchanged.
What happens on each cell render?
For every cell the formatter does 4 things:
1. Loads active Format Columns for that column that include a `DisplayFormat`
2. Picks the **most relevant** Format Column — as per the Display Format Precedence Rules described above
3. Calls **`resolveDisplayFormat`** on that column’s `DisplayFormat` value
4. Runs the resolved formatter (`NumberFormatter`, `DateFormatter`, or `StringFormatter`) via AdapTable’s internal formatting helpers to produce the display value
```text
Format Column (state)
→ AG Grid valueFormatter (per column)
→ most relevant Format Column for this cell
→ resolveDisplayFormat (preset name → AdaptableFormat object)
→ system formatter (+ optional custom handlers) → display text
```
Resolving presets and formatter objects
`DisplayFormat` in Format Column state is either:
- A **numeric preset name** (e.g. `'Dollar'`) — stored as a string. At render time AdapTable displays it appropriately
State is not rewritten unless the user edits the format in the UI (which typically persists the long form)
- A full **`AdaptableFormat` object** — `{ Formatter: '…', Options: { … } }` for number, date, or string. Used as-is
Date columns always use the object form in state (`DateFormatter` + `Pattern`).
Date “presets” in the wizard only fill in `Pattern`; they are not preset names on `DisplayFormat`
Custom Display Formats
If you register [Custom Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-custom/index.md) in Format Column options, their ids can appear on `Options.CustomDisplayFormats`.
Those handlers run in the same formatting pipeline after the system formatter options are applied.
API usage
The API method `formatColumnApi.getDisplayFormatForColumn` returns the resolved `AdaptableFormat` for a column (preset names are expanded there too).
This is useful when building summaries, tooltips, or other UI that should match grid display.
---
# Custom Display Format
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-custom
- Custom Display Formats can be provided when those provided by AdapTable are insufficient
The Display Format options provided by AdapTable fit the vast majority of real-life use cases.
However, if required, Developers can supply bespoke Custom Display Formatters at design time.
This is done via a 2-stage process:
1. Defining the Custom Formatter in `customDisplayFormatters` property in [Format Column Options](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
2. Referencing the Custom Formatter in [Format Column Initial State](https://www.adaptabletools.com/docs/handbook-styling-formatting-technical-reference/index.md)
### `customDisplayFormatters`
Custom Formatters used in Format Column Module
[`CustomDisplayFormatter[]`](https://www.adaptabletools.com/docs/reference/customdisplayformatter.md)
This property is used to supplement the Display Formatters provided by AdapTable.
The full definition of the [`CustomDisplayFormatter[]`](https://www.adaptabletools.com/docs/reference/customdisplayformatter.md) object is:
| Property | Type | Description |
| --- | --- | --- |
| [handler](https://www.adaptabletools.com/docs/reference/customdisplayformatter.md#handler) | `(customDisplayFormatterContext: `[`CustomDisplayFormatterContext`](https://www.adaptabletools.com/docs/reference/customdisplayformattercontext.md)`) => any` | Function used to render the Custom Display Format |
| [id](https://www.adaptabletools.com/docs/reference/customdisplayformatter.md#id) | `string` | Custom Format Id |
| [label](https://www.adaptabletools.com/docs/reference/customdisplayformatter.md#label) | `string` | Custom Format Description |
| [scope](https://www.adaptabletools.com/docs/reference/customdisplayformatter.md#scope) | [`ColumnScope`](https://www.adaptabletools.com/docs/reference/columnscope.md) | Used by Format Columns wizard to show where Custom Display Format can be applied |
Handler Function
As can be seen it includes a `handler` function which AdapTable invokes when the cell is rendered:
```js
handler: (customDisplayFormatterContext: CustomDisplayFormatterContext) => any;
```
The function receives a [`CustomDisplayFormatterContext`](https://www.adaptabletools.com/docs/reference/customdisplayformattercontext.md) object which provides details of the cell, column and row (and returns the custom display format). The object definition is:
| Property | Type | Description |
| --- | --- | --- |
| [adaptableColumn](https://www.adaptabletools.com/docs/reference/customdisplayformattercontext.md#adaptablecolumn) | [`AdaptableColumn`](https://www.adaptabletools.com/docs/reference/adaptablecolumn.md) | Column where Custom Display Format will apply |
| [cellValue](https://www.adaptabletools.com/docs/reference/customdisplayformattercontext.md#cellvalue) | `any` | Non-formatted Cell Value |
| [rowNode](https://www.adaptabletools.com/docs/reference/customdisplayformattercontext.md#rownode) | `IRowNode` | Node where Custom Display Format will apply |
| [adaptableContext](https://www.adaptabletools.com/docs/reference/customdisplayformattercontext.md#adaptablecontext) | `any` | Custom application Context provided in `AdaptableOptions.adaptableContext` |
Using a Custom Display Formatter
A CustomDisplayFormatter is used as follows:
```ts
formatColumnOptions: {
customDisplayFormatters: [
{
id: 'bigNumberCustomFormat',
label: 'Big Number Custom Format',
scope: {
DataTypes: ['number'],
},
handler: (customDisplayFormatterContext: CustomDisplayFormatterContext) => {
const cellValue: number = customDisplayFormatterContext.cellValue as number;
return (cellValue > 10000) ? cellValue / 1000 + 'K' : cellValue;
},
},
],
},
```
would then be referenced in the FormatColumn section of Initial Adaptable State;
```ts
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-number-115',
Scope: {
DataTypes: ['number'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
CustomDisplayFormats: ['bigNumberCustomFormat'],
},
},
},
],
},
```
- Only use these when AdapTable's System Display Formats are insufficient for your use case
- You might also find that a [Template Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-template/index.md) provides what you require with less complexity
Each definition includes a `handler` function which AdapTable invokes when the cell is rendered and which should return the custom display format.
- The `scope` property in the Custom Formatter tells AdapTable which columns in the UI Wizard should offer the option
- The actual wiring up is done using the `Scope` propery in the relevant Format Column Definition
**Example: Column Formatting: Custom Formatter**
Column Formatting with a Custom Display Formatter
- This example provides 4 Custom Display Formats - using the `CustomDisplayFormatterContext` object for evaluation:
- for `License` column where the word 'License' is removed
- for `Created` column where we just show the Day of the Week
- for `Issue Change` column where we replace 0 values with a '-'
- for `Gitub Stars` column where values over one million display M, over one thousand display 'K', or display normally
- Note: We still also use some of the display formats shipped by AdapTable (i.e. `Licence` is UPPER CASE and `Created` is _italicised_)
```ts
import {
AdaptableOptions,
CustomDisplayFormatterContext,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Custom Display Formats',
formatColumnOptions: {
customDisplayFormatters: [
// Provide Custom Format for license column
{
id: 'licenseCustomFormat',
label: 'License Format',
scope: {
ColumnIds: ['license'],
},
handler: (
customDisplayFormatterContext: CustomDisplayFormatterContext
) => {
const cellValue: string =
customDisplayFormatterContext.cellValue as string;
return cellValue.replaceAll('License', '');
},
},
// Provide Custom Format for Issue Change Column
{
id: 'weekIssueChangeFormat',
label: 'Week Change Custom Format',
scope: {ColumnIds: ['week_issue_change']},
handler: (
customDisplayFormatterContext: CustomDisplayFormatterContext
) => {
const currentvalue: any = customDisplayFormatterContext.cellValue;
return currentvalue === 0 ? '-' : currentvalue;
},
},
// Provide Custom Format for all Date Columns
{
id: 'weekDayCustomFormat',
label: 'Created At Format',
scope: {DataTypes: ['date']},
handler: (
customDisplayFormatterContext: CustomDisplayFormatterContext
) => {
if (
!customDisplayFormatterContext ||
!customDisplayFormatterContext.cellValue
) {
return undefined;
}
return new Date(
customDisplayFormatterContext.cellValue
).toLocaleString('en-us', {weekday: 'long'});
},
},
// Provide Custom Format for all Numeric Columns
{
id: 'hundredThousandFormat',
label: 'Hundred Thousand Format',
scope: {DataTypes: ['number']},
handler: (
customDisplayFormatterContext: CustomDisplayFormatterContext
) => {
const currentvalue: number = customDisplayFormatterContext.cellValue;
if (currentvalue > 1000000) {
return (currentvalue / 1000000).toFixed(2) + 'M';
}
if (currentvalue > 1000) {
return (currentvalue / 1000).toFixed(2) + 'K';
}
return currentvalue;
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'license',
'github_stars',
'closed_issues_count',
'created_at',
'closed_pr_count',
'updated_at',
'week_issue_change',
'github_watchers',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
// Wire up the License Custom Format
{
Name: 'formatColumn-license',
Scope: {
ColumnIds: ['license'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
CustomDisplayFormats: ['licenseCustomFormat'],
Case: 'Upper',
},
},
},
// Wire up the Date Custom Format for Created Column
{
Name: 'formatColumn-created_at',
Scope: {
ColumnIds: ['created_at'],
},
Style: {
FontStyle: 'Italic',
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
CustomDisplayFormats: ['weekDayCustomFormat'],
},
},
},
// Wire up the Week Issue Change Custom Format
{
Name: 'formatColumn-week_issue_change',
Scope: {ColumnIds: ['week_issue_change']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {CustomDisplayFormats: ['weekIssueChangeFormat']},
},
},
// Wire up the Nueric Custom Format for Github Stars column
{
Name: 'formatColumn-github_stars',
Scope: {ColumnIds: ['github_stars']},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {CustomDisplayFormats: ['hundredThousandFormat']},
},
},
],
},
},
};
```
```ts
export const rowData = [
{
id: 10270250,
name: 'react',
full_name: 'facebook/react',
html_url: 'https://github.com/facebook/react',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2013-05-24T16:15:54').toDateString(),
updated_at: new Date('2021-12-20T09:03:49').toDateString(),
pushed_at: new Date('2021-12-19T14:34:59').toDateString(),
homepage: 'https://reactjs.org',
github_stars: 8794429,
language: 'JavaScript',
forks_count: 36403,
open_issues_count: 920,
license: 'MIT License',
topics: ['declarative', 'frontend', 'javascript', 'library', 'react', 'ui'],
github_watchers: 6671,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 10326,
open_pr_count: 249,
closed_pr_count: 11408,
week_issue_change: 5,
},
{
id: 24195339,
name: 'angular',
full_name: 'angular/angular',
html_url: 'https://github.com/angular/angular',
description: 'The modern web developer’s platform',
created_at: new Date('2014-09-18T16:12:01').toDateString(),
updated_at: new Date('2021-12-20T08:37:07').toDateString(),
pushed_at: new Date('2021-12-19T21:54:01').toDateString(),
homepage: 'https://angular.io',
github_stars: 78548,
language: 'TypeScript',
forks_count: 20569,
open_issues_count: 1889,
license: 'MIT License',
topics: [
'angular',
'javascript',
'pwa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 3119,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 21706,
open_pr_count: 159,
closed_pr_count: 20052,
week_issue_change: 12,
},
{
id: 11730342,
name: 'vue',
full_name: 'vuejs/vue',
html_url: 'https://github.com/vuejs/vue',
description:
'🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.',
created_at: new Date('2013-07-29T03:24:51').toDateString(),
updated_at: new Date('2021-12-20T08:47:06').toDateString(),
pushed_at: new Date('2021-12-20T08:10:16').toDateString(),
homepage: 'http://vuejs.org',
github_stars: 7912435,
language: 'JavaScript',
forks_count: 30945,
open_issues_count: 546,
license: 'MIT License',
topics: ['framework', 'frontend', 'javascript', 'vue'],
github_watchers: 6187,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 9318,
open_pr_count: 224,
closed_pr_count: 1878,
week_issue_change: 0,
},
{
id: 74293321,
name: 'svelte',
full_name: 'sveltejs/svelte',
html_url: 'https://github.com/sveltejs/svelte',
description: 'Cybernetically enhanced web apps',
created_at: new Date('2016-11-20T18:13:05').toDateString(),
updated_at: new Date('2021-12-20T08:56:37').toDateString(),
pushed_at: new Date('2021-12-19T14:53:30').toDateString(),
homepage: 'https://svelte.dev',
github_stars: 539735,
language: 'TypeScript',
forks_count: 2584,
open_issues_count: 604,
license: 'MIT License',
topics: ['compiler', 'template', 'ui'],
github_watchers: 874,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3549,
open_pr_count: 104,
closed_pr_count: 2738,
week_issue_change: 14,
},
{
id: 224663696,
name: 'alpine',
full_name: 'alpinejs/alpine',
html_url: 'https://github.com/alpinejs/alpine',
description:
'A rugged, minimal framework for composing JavaScript behavior in your markup. ',
created_at: new Date('2019-11-28T13:51:55').toDateString(),
updated_at: new Date('2021-12-20T08:12:43').toDateString(),
pushed_at: new Date('2021-12-14T16:02:26').toDateString(),
homepage: 'https://alpinejs.dev',
github_stars: 938,
language: 'HTML',
forks_count: 837,
open_issues_count: 19,
license: 'MIT License',
topics: [],
github_watchers: 202,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 544,
open_pr_count: 13,
closed_pr_count: 546,
week_issue_change: 0,
},
{
id: 95797174,
name: 'lit',
full_name: 'lit/lit',
html_url: 'https://github.com/lit/lit',
description:
'Lit is a simple library for building fast, lightweight web components.',
created_at: new Date('2017-06-29T16:27:16').toDateString(),
updated_at: new Date('2021-12-20T07:20:35').toDateString(),
pushed_at: new Date('2021-12-17T03:45:26').toDateString(),
homepage: 'https://lit.dev',
github_stars: 97952,
language: 'JavaScript',
forks_count: 528,
open_issues_count: 207,
license: 'BSD 3-Clause',
topics: ['html-templates', 'lit', 'lit-element', 'lit-html'],
github_watchers: 204,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 895,
open_pr_count: 53,
closed_pr_count: 1138,
week_issue_change: -45,
},
{
id: 76694515,
name: 'stimulus',
full_name: 'hotwired/stimulus',
html_url: 'https://github.com/hotwired/stimulus',
description: 'A modest JavaScript framework for the HTML you already have',
created_at: new Date('2016-12-17T00:19:29').toDateString(),
updated_at: new Date('2021-12-20T07:20:01').toDateString(),
pushed_at: new Date('2021-12-17T20:47:34').toDateString(),
homepage: 'https://stimulus.hotwired.dev/',
github_stars: 118049,
language: 'TypeScript',
forks_count: 316,
open_issues_count: 17,
license: 'MIT License',
topics: [],
github_watchers: 221,
has_projects: false,
has_wiki: true,
has_pages: false,
closed_issues_count: 282,
open_pr_count: 5,
closed_pr_count: 191,
week_issue_change: -11,
},
{
id: 1801829,
name: 'ember.js',
full_name: 'emberjs/ember.js',
html_url: 'https://github.com/emberjs/ember.js',
description:
'Ember.js - A JavaScript framework for creating ambitious web applications',
created_at: new Date('2011-05-25T23:39:40').toDateString(),
updated_at: new Date('2021-12-19T07:57:31').toDateString(),
pushed_at: new Date('2021-12-20T07:15:54').toDateString(),
homepage: 'https://emberjs.com',
github_stars: 22093,
language: 'JavaScript',
forks_count: 4253,
open_issues_count: 427,
license: 'MIT License',
topics: ['ember', 'hacktoberfest', 'javascript', 'javascript-framework'],
github_watchers: 908,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 6187,
open_pr_count: 94,
closed_pr_count: 9574,
week_issue_change: -22,
},
{
id: 82095231,
name: 'stencil',
full_name: 'ionic-team/stencil',
html_url: 'https://github.com/ionic-team/stencil',
description:
'A toolchain for building scalable, enterprise-ready component systems on top of TypeScript.',
created_at: new Date('2017-02-15T18:57:07').toDateString(),
updated_at: new Date('2021-12-20T05:46:50').toDateString(),
pushed_at: new Date('2021-12-16T21:15:17').toDateString(),
homepage: 'https://stenciljs.com',
github_stars: 9884,
language: 'TypeScript',
forks_count: 641,
open_issues_count: 499,
license: 'Other',
topics: [
'custom-elements',
'ionic',
'progressive-web-app',
'pwa',
'ssg',
'ssr',
'static-site-generator',
'stencil',
'stenciljs',
'typescript',
'webcomponents',
],
github_watchers: 203,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 1929,
open_pr_count: 46,
closed_pr_count: 743,
week_issue_change: 0,
},
{
id: 130884470,
name: 'solid',
full_name: 'solidjs/solid',
html_url: 'https://github.com/solidjs/solid',
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',
created_at: new Date('2018-04-24T16:36:27').toDateString(),
updated_at: new Date('2021-12-20T08:29:47').toDateString(),
pushed_at: new Date('2021-12-19T21:06:01').toDateString(),
homepage: 'https://solidjs.com',
github_stars: 819,
language: 'TypeScript',
forks_count: 330,
open_issues_count: 21,
license: 'MIT License',
topics: [
'declarative',
'fine-grained',
'javascript',
'jsx',
'performance',
'proxies',
'reactive',
'solid',
],
github_watchers: 161,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 366,
open_pr_count: 3,
closed_pr_count: 164,
week_issue_change: 0,
},
{
id: 17814354,
name: 'mithril.js',
full_name: 'MithrilJS/mithril.js',
html_url: 'https://github.com/MithrilJS/mithril.js',
description: 'A JavaScript Framework for Building Brilliant Applications',
created_at: new Date('2014-03-17T01:59:39').toDateString(),
updated_at: new Date('2021-12-20T03:17:55').toDateString(),
pushed_at: new Date('2021-11-24T10:16:47').toDateString(),
homepage: 'https://mithril.js.org',
github_stars: 130164,
language: 'JavaScript',
forks_count: 940,
open_issues_count: 173,
license: 'MIT License',
topics: [
'framework',
'javascript',
'mithril',
'router',
'vdom',
'virtual-dom',
'xhr',
],
github_watchers: 324,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1368,
open_pr_count: 28,
closed_pr_count: 1144,
week_issue_change: 57,
},
{
id: 167174,
name: 'jquery',
full_name: 'jquery/jquery',
html_url: 'https://github.com/jquery/jquery',
description: 'jQuery JavaScript Library',
created_at: new Date('2009-04-03T15:20:14').toDateString(),
updated_at: new Date('2021-12-20T06:13:48').toDateString(),
pushed_at: new Date('2021-12-17T16:50:04').toDateString(),
homepage: 'https://jquery.com',
github_stars: 55666,
language: 'JavaScript',
forks_count: 20187,
open_issues_count: 84,
license: 'MIT License',
topics: ['jquery'],
github_watchers: 3306,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 2083,
open_pr_count: 13,
closed_pr_count: 2692,
week_issue_change: 15,
},
{
id: 5532320,
name: 'polymer',
full_name: 'Polymer/polymer',
html_url: 'https://github.com/Polymer/polymer',
description: 'Our original Web Component library.',
created_at: new Date('2012-08-23T20:56:30').toDateString(),
updated_at: new Date('2021-12-19T05:05:03').toDateString(),
pushed_at: new Date('2021-12-07T22:20:44').toDateString(),
homepage: 'https://polymer-library.polymer-project.org/',
github_stars: 21724,
language: 'HTML',
forks_count: 2026,
open_issues_count: 281,
license: 'Other',
topics: ['polymer', 'web-components'],
github_watchers: 894,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 3648,
open_pr_count: 26,
closed_pr_count: 1404,
week_issue_change: 9,
},
{
id: 952189,
name: 'backbone',
full_name: 'jashkenas/backbone',
html_url: 'https://github.com/jashkenas/backbone',
description:
'Give your JS App some Backbone with Models, Views, Collections, and Events',
created_at: new Date('2010-09-30T19:41:28').toDateString(),
updated_at: new Date('2021-12-19T05:50:57').toDateString(),
pushed_at: new Date('2020-05-19T16:52:55').toDateString(),
homepage: 'http://backbonejs.org',
github_stars: 278940,
language: 'JavaScript',
forks_count: 5608,
open_issues_count: 85,
license: 'MIT License',
topics: [],
github_watchers: 1365,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 2335,
open_pr_count: 32,
closed_pr_count: 1797,
week_issue_change: 0,
},
{
id: 757363,
name: 'knockout',
full_name: 'knockout/knockout',
html_url: 'https://github.com/knockout/knockout',
description:
'Knockout makes it easier to create rich, responsive UIs with JavaScript',
created_at: new Date('2010-07-05T08:08:34').toDateString(),
updated_at: new Date('2021-12-18T17:20:52').toDateString(),
pushed_at: new Date('2021-10-09T07:42:49').toDateString(),
homepage: 'http://knockoutjs.com/',
github_stars: 106122,
language: 'JavaScript',
forks_count: 1571,
open_issues_count: 362,
license: 'Other',
topics: ['data-binding', 'javascript', 'knockout', 'mvvm'],
github_watchers: 549,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1534,
open_pr_count: 72,
closed_pr_count: 670,
week_issue_change: 63,
},
{
id: 191051391,
name: 'redwood',
full_name: 'redwoodjs/redwood',
html_url: 'https://github.com/redwoodjs/redwood',
description: 'The App Framework for Startups',
created_at: new Date('2019-06-09T20:17:57').toDateString(),
updated_at: new Date('2021-12-20T01:41:55').toDateString(),
pushed_at: new Date('2021-12-20T00:37:09').toDateString(),
homepage: 'https://redwoodjs.com',
github_stars: 103334,
language: 'TypeScript',
forks_count: 431,
open_issues_count: 269,
license: 'MIT License',
topics: [
'apollo',
'graphql',
'hacktoberfest',
'jamstack',
'prisma',
'react',
],
github_watchers: 80,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 1071,
open_pr_count: 35,
closed_pr_count: 2602,
week_issue_change: 14,
},
{
id: 36040894,
name: 'gatsby',
full_name: 'gatsbyjs/gatsby',
html_url: 'https://github.com/gatsbyjs/gatsby',
description: 'Build blazing fast, modern apps and websites with React',
created_at: new Date('2015-05-21T22:43:05').toDateString(),
updated_at: new Date('2021-12-20T09:04:22').toDateString(),
pushed_at: new Date('2021-12-20T08:04:34').toDateString(),
homepage: 'https://www.gatsbyjs.com',
github_stars: 51931,
language: 'JavaScript',
forks_count: 10049,
open_issues_count: 359,
license: 'MIT License',
topics: [
'blog',
'compiler',
'documentation-tool',
'gatsby',
'graphql',
'react',
'static-site-generator',
'web-app',
],
github_watchers: 853,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 12975,
open_pr_count: 180,
closed_pr_count: 19058,
week_issue_change: -34,
},
{
id: 26316966,
name: 'cyclejs',
full_name: 'cyclejs/cyclejs',
html_url: 'https://github.com/cyclejs/cyclejs',
description:
'A functional and reactive JavaScript framework for predictable code',
created_at: new Date('2014-11-07T11:28:45').toDateString(),
updated_at: new Date('2021-12-20T06:39:49').toDateString(),
pushed_at: new Date('2021-12-17T11:03:37').toDateString(),
homepage: 'http://cycle.js.org',
github_stars: 99499,
language: 'TypeScript',
forks_count: 421,
open_issues_count: 102,
license: 'MIT License',
topics: [
'cyclejs',
'framework',
'functional-programming',
'hacktoberfest',
'javascript',
'reactive-programming',
'rxjs',
'typescript',
],
github_watchers: 205,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 563,
open_pr_count: 26,
closed_pr_count: 301,
week_issue_change: -2,
},
{
id: 42283287,
name: 'preact',
full_name: 'preactjs/preact',
html_url: 'https://github.com/preactjs/preact',
description:
'⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.',
created_at: new Date('2015-09-11T02:40:18').toDateString(),
updated_at: new Date('2021-12-20T09:02:15').toDateString(),
pushed_at: new Date('2021-12-17T23:21:58').toDateString(),
homepage: 'https://preactjs.com',
github_stars: 3025538,
language: 'JavaScript',
forks_count: 1702,
open_issues_count: 222,
license: 'MIT License',
topics: [
'components',
'dom',
'jsx',
'preact',
'react',
'vdom',
'virtual-dom',
],
github_watchers: 425,
has_projects: true,
has_wiki: true,
has_pages: true,
closed_issues_count: 1309,
open_pr_count: 78,
closed_pr_count: 1729,
week_issue_change: -12,
},
{
id: 13142126,
name: 'riot',
full_name: 'riot/riot',
html_url: 'https://github.com/riot/riot',
description: 'Simple and elegant component-based UI library',
created_at: new Date('2013-09-27T05:21:01').toDateString(),
updated_at: new Date('2021-12-20T05:17:31').toDateString(),
pushed_at: new Date('2021-12-17T20:09:25').toDateString(),
homepage: 'https://riot.js.org',
github_stars: 145997,
language: 'JavaScript',
forks_count: 1032,
open_issues_count: 5,
license: 'Other',
topics: [
'client-side',
'customelement',
'customelements',
'customtags',
'elegant',
'framework',
'javascript',
'lite',
'minimal',
'simple',
'view',
'webcomponents',
],
github_watchers: 412,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 2147,
open_pr_count: 0,
closed_pr_count: 755,
week_issue_change: 0,
},
{
id: 121594173,
name: 'aurelia',
full_name: 'aurelia/aurelia',
html_url: 'https://github.com/aurelia/aurelia',
description:
'Aurelia 2, a standards-based, front-end framework designed for high-performing, ambitious applications.',
created_at: new Date('2018-02-15T05:22:58').toDateString(),
updated_at: new Date('2021-12-19T04:23:43').toDateString(),
pushed_at: new Date('2021-11-28T16:21:43').toDateString(),
homepage: '',
github_stars: 987,
language: 'TypeScript',
forks_count: 121,
open_issues_count: 143,
license: 'MIT License',
topics: [
'aurelia',
'cordova',
'cross-platform',
'electron',
'framework',
'frontend',
'html',
'javascript',
'javascript-framework',
'mobile',
'pwa',
'single-page-applications',
'spa',
'typescript',
'web',
'web-framework',
'web-performance',
],
github_watchers: 66,
has_projects: true,
has_wiki: false,
has_pages: false,
closed_issues_count: 214,
open_pr_count: 17,
closed_pr_count: 959,
week_issue_change: 0,
},
{
id: 70107786,
name: 'next.js',
full_name: 'vercel/next.js',
html_url: 'https://github.com/vercel/next.js',
description: 'The React Framework',
created_at: new Date('2016-10-05T23:32:51').toDateString(),
updated_at: new Date('2021-12-20T08:57:47').toDateString(),
pushed_at: new Date('2021-12-20T08:21:58').toDateString(),
homepage: 'https://nextjs.org',
github_stars: 7884046,
language: 'JavaScript',
forks_count: 15787,
open_issues_count: 1361,
license: 'MIT License',
topics: [
'blog',
'browser',
'compiler',
'components',
'hybrid',
'nextjs',
'node',
'react',
'server-rendering',
'ssg',
'static',
'static-site-generator',
'universal',
'vercel',
],
github_watchers: 1224,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 10320,
open_pr_count: 254,
closed_pr_count: 9849,
week_issue_change: 63,
},
{
id: 71995937,
name: 'nuxt.js',
full_name: 'nuxt/nuxt.js',
html_url: 'https://github.com/nuxt/nuxt.js',
description: 'The Intuitive Vue(2) Framework',
created_at: new Date('2016-10-26T11:18:47').toDateString(),
updated_at: new Date('2021-12-20T08:27:45').toDateString(),
pushed_at: new Date('2021-12-20T08:05:15').toDateString(),
homepage: 'https://nuxtjs.org',
github_stars: 389997,
language: 'JavaScript',
forks_count: 3157,
open_issues_count: 464,
license: 'Other',
topics: [
'framework',
'isomorphic',
'nuxt',
'server-rendering',
'ssr',
'universal',
'vue',
'vue-router',
'vuex',
'web-app',
],
github_watchers: 772,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 6129,
open_pr_count: 30,
closed_pr_count: 2869,
week_issue_change: -18,
},
{
id: 3214406,
name: 'meteor',
full_name: 'meteor/meteor',
html_url: 'https://github.com/meteor/meteor',
description: 'Meteor, the JavaScript App Platform',
created_at: new Date('2012-01-19T01:58:17').toDateString(),
updated_at: new Date('2021-12-20T06:36:27').toDateString(),
pushed_at: new Date('2021-12-17T18:10:08').toDateString(),
homepage: 'https://www.meteor.com',
github_stars: 42742,
language: 'JavaScript',
forks_count: 5187,
open_issues_count: 120,
license: 'Other',
topics: [
'build-system',
'framework',
'hacktoberfest',
'javascript',
'meteor',
'mongodb',
'nodejs',
'npm',
'reactive-programming',
'zero-configuration',
],
github_watchers: 1642,
has_projects: true,
has_wiki: true,
has_pages: false,
closed_issues_count: 8537,
open_pr_count: 24,
closed_pr_count: 2998,
week_issue_change: 21,
},
{
id: 43695474,
name: 'quasar',
full_name: 'quasarframework/quasar',
html_url: 'https://github.com/quasarframework/quasar',
description:
'Quasar Framework - Build high-performance VueJS user interfaces in record time',
created_at: new Date('2015-10-05T15:45:36').toDateString(),
updated_at: new Date('2021-12-20T08:26:07').toDateString(),
pushed_at: new Date('2021-12-19T23:18:50').toDateString(),
homepage: 'https://quasar.dev',
github_stars: 210095,
language: 'JavaScript',
forks_count: 2543,
open_issues_count: 367,
license: 'MIT License',
topics: [
'android',
'browser-extension',
'electron',
'ios',
'javascript',
'material',
'material-components',
'material-design',
'material-theme',
'pwa',
'quasar-framework',
'server-side-rendering',
'ssr',
'vue',
'vue-component',
'vue-components',
'vue2',
'vuejs',
'vuejs2',
],
github_watchers: 488,
has_projects: false,
has_wiki: false,
has_pages: false,
closed_issues_count: 6097,
open_pr_count: 97,
closed_pr_count: 3424,
week_issue_change: 1,
},
];
```
---
# Date Display Format
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-date
- AdapTable provides a number of Display Formats to be used with Date Columns
Users can use the [`Date Formatter`](https://www.adaptabletools.com/docs/reference/dateformatteroptions.md) to set their own date pattern (or select one of the presets).
The object has a single `Pattern` property:
| Property | Type | Description |
| --- | --- | --- |
| [Pattern](https://www.adaptabletools.com/docs/reference/dateformatteroptions.md#pattern) | `string` | Pattern to use for Date Format |
Find the full list of available DateTime patterns at the [unicode website](https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
### Date Presets
Similar to numeric columns, AdapTable provides some presets for commonly used Date Formats:
| Preset | Example (using 5 August 2023 at 10:30pm) |
| ----------------------- | ---------------------------------------- |
| MM/dd/yyyy | 08/05/2023 |
| dd-MM-yyyyy | 05-08-2023 |
| MMMM do yyyy, h:mm:ss a | August 5th 2023, 10:30:00 PM |
| EEEE | Saturday |
| MMM do yyyy | Aug 5th 2023 |
| yyyyMMdd | 20230805 |
| HH:mm:ss | 22:30:00 |
**Example: Column Formatting: Date Display Formats**
Column Formatting with Date Display Formats
- This example shows 3 different Date Formats
- `Created` has a format of 'yyyy/MM/dd'
- `Updated` has a format of 'MMM do yyyy'
- `Pushed` has a format of 'EEEE'
### Expand to see the Date Display Formats
```ts
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-created_at-112',
Scope: {
ColumnIds: ['created_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'yyyy/MM/dd',
},
},
},
{
Name: 'FormatColumn-updated_at-113',
Scope: {
ColumnIds: ['updated_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy',
},
},
},
{
Name: 'FormatColumn-pushed_at-114',
Scope: {
ColumnIds: ['pushed_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'EEEE',
},
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Date Display Formats',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'created_at',
'updated_at',
'pushed_at',
'week_issue_change',
'github_stars',
'closed_pr_count',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-created_at',
Scope: {
ColumnIds: ['created_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'yyyy/MM/dd',
},
},
},
{
Name: 'formatColumn-updated_at',
Scope: {
ColumnIds: ['updated_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'MMM do yyyy',
},
},
},
{
Name: 'formatColumn-pushed_at',
Scope: {
ColumnIds: ['pushed_at'],
},
DisplayFormat: {
Formatter: 'DateFormatter',
Options: {
Pattern: 'EEEE',
},
},
},
],
},
},
};
```
---
# Numeric Display Format
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number
- AdapTable provides a number of Display Formats to be used with Numeric Columns
AdapTable ships with a number of System Number Display Formats.
These are designed to provide Display Formats for numeric columns.
They are contained in the [`Number Formatter`](https://www.adaptabletools.com/docs/reference/number) object defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [Abs](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#abs) | `boolean` | Returns absolute value of cell value |
| [Ceiling](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#ceiling) | `boolean` | Returns smallest integer greater than cell value |
| [Content](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#content) | `string \| number` | Replaces cell value with supplied value (that can contain Template Literals) |
| [Empty](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#empty) | `boolean` | Show nothing in cell (but underlying value remains) |
| [Floor](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#floor) | `boolean` | Returns largest integer cell value |
| [FractionDigits](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#fractiondigits) | `number` | Number of digits to show in Fractions (up to 20) |
| [FractionSeparator](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#fractionseparator) | `string` | Separator to use in fractions |
| [IntegerDigits](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#integerdigits) | `number` | Number of digits to show for Integers (up to 20) |
| [IntegerSeparator](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#integerseparator) | `string` | Separator to use in Integers |
| [Multiplier](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#multiplier) | `number` | Multiplier to use on cell value |
| [Notation](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#notation) | `'standard' \| 'scientific'` | Numeric notation to use when rendering the value. |
| [Parentheses](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#parentheses) | `boolean` | Shows negative numbers in parentheses |
| [Prefix](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#prefix) | `string` | Prefix to use before cell value |
| [Round](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#round) | `boolean` | Rounds cell value |
| [Suffix](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#suffix) | `string` | Suffix to use after cell value |
| [Truncate](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#truncate) | `boolean` | Truncates cell value |
| [ZeroDisplay](https://www.adaptabletools.com/docs/reference/numberformatteroptions.md#zerodisplay) | `string` | When the numeric value is zero (after multiplier and rounding): - omitted / undefined, or `'0'` — use normal formatting (e.g. `0`, `0.00`) - `''` — show a blank cell (user cleared the default `0` in the wizard) - any other string — show that text (e.g. `-`, `—`) |
**Example: Column Formatting: Numeric Display Formats**
Column Formatting with Numeric Display Formats
- In this example 2 Format Columns use a full `NumberFormatter` object (not presets):
- `Github Stars` — `Multiplier` `0.001` and suffix `K` (one decimal place)
- `Issue Change` — negative values in **parentheses** via `Parentheses: true` (no fraction digits)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Numeric Display Format Options',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'github_stars',
'week_issue_change',
'closed_pr_count',
'open_pr_count',
'updated_at',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 1,
FractionSeparator: '.',
IntegerSeparator: ',',
Multiplier: 0.001,
Suffix: 'K',
},
},
},
{
Name: 'formatColumn-week_issue_change',
Scope: {
ColumnIds: ['week_issue_change'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
FractionDigits: 0,
FractionSeparator: '.',
IntegerSeparator: ',',
Parentheses: true,
},
},
},
],
},
},
};
```
## Numeric Presets
AdapTable provides **15 preset numeric Display Formats** as a convenience feature.
These presets cover the most common use cases, and general-purpose number formats, out of the box, e.g. currency, magnitude, rate etc
Each preset is a short-hand name (e.g. `'Dollar'`, `'Percentage'`) containing a set of numeric format options.
- This allows you to specify the preset (e.g. `Dollar`) without supplying the details (e.g. `FractionDigits`, `Prefix`, etc.)
- AdapTable will convert the preset into a fully formed Display Format at runtime on your behalf
You can use a preset directly in Format Column Initial State, by simply assigning its name to `DisplayFormat`:
```ts
DisplayFormat: 'Dollar';
```
- You can later fall back to the long-form `NumberFormatter` object if you need to tweak any of the underlying options
- e.g. add a custom suffix, fraction digits, multiplier, etc.
### UI Wizard
The presets are also available in the Format Column [UI Wizard](https://www.adaptabletools.com/docs/ui-settings-panel-wizards/index.md).
This allows run-time users to create display formats quickly.
The wizard arranges the Presets into 4 groups: `Currencies`, `Magnitude`, `General Numeric` and `Specialised`.
The Presets provided by AdapTable are:
| Name (and UI Label) | Category | Raw Value | Display Format |
| ------------------- | ----------- | ------------ | -------------- |
| Dollar | Currency | `123.4567` | `$123.46` |
| Sterling | Currency | `123.4567` | `£123.46` |
| Euro | Currency | `123.4567` | `€123.46` |
| Yen | Currency | `1234` | `¥1,234` |
| Bitcoin | Currency | `0.12345678` | `₿0.12345678` |
| K (`Thousand`) | Magnitude | `123456` | `123.456K` |
| M (`Million`) | Magnitude | `123456789` | `123.456789M` |
| B (`Billion`) | Magnitude | `1234567890` | `1.23456789B` |
| Integer | General | `1234.56` | `1,235` |
| Decimal | General | `1234.5678` | `1,234.57` |
| Percentage | General | `0.54321` | `54.32%` |
| Scientific | General | `1234567` | `1.23E6` |
| Accounting | Specialised | `-1234.56` | `(1,234.56)` |
| FX Rate (`FXRate`) | Specialised | `1.23456` | `1.2346` |
| bps (`BasisPoints`) | Specialised | `0.0125` | `125 bps` |
- **Accounting** prints negative numbers in parentheses (positives render plain) — a long-standing finance convention
- **Basis Points** assumes the raw value is a decimal rate (1 = 100%), multiplies by `10000` and appends ` bps`
- **Scientific** uses JavaScript's `Intl.NumberFormat` with `notation: 'scientific'`, capped to 2 fraction digits
**Example: Column Formatting: Numeric Display Format Presets**
Column Formatting with Numeric Display Format Presets
- In this example, 3 Format Columns have `DisplayFormat` set to a **preset name** directly (AdapTable resolves these at runtime):
- `Open/Total Issues` — `'Percentage'` (calculated ratio column)
- `Issue Change` — `'Accounting'` (negatives in parentheses)
- `Github Stars` — `'Thousand'` (values shown in thousands with a `K` suffix)
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Numeric Display Format Presets',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'open-total-issue-ratio',
'github_stars',
'week_issue_change',
'closed_pr_count',
'updated_at',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-open-total-issue-ratio',
Scope: {
ColumnIds: ['open-total-issue-ratio'],
},
DisplayFormat: 'Percentage',
},
{
Name: 'formatColumn-week_issue_change',
Scope: {
ColumnIds: ['week_issue_change'],
},
DisplayFormat: 'Accounting',
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: 'Thousand',
},
],
},
CalculatedColumn: {
CalculatedColumns: [
{
ColumnId: 'open-total-issue-ratio',
Query: {
ScalarExpression:
'[open_pr_count]/([open_pr_count]+[closed_pr_count])',
},
CalculatedColumnSettings: {
DataType: 'number',
},
FriendlyName: 'Open/Total Issues',
},
],
},
},
};
```
---
# String Display Format
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-string
- AdapTable provides a number of Display Formats to be used with String Columns
AdapTable ships with a number of System String Display Formats.
These are designed to provide Display Formats for string columns.
They are contained in the [`String Formatter`](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md) object defined as follows:
| Property | Type | Description |
| --- | --- | --- |
| [Case](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md#case) | `'Upper' \| 'Lower' \| 'Sentence'` | Sets text to Upper, Lower or Sentence case |
| [Content](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md#content) | `string` | Replaces cell value; useful when using Condition (e.g. replace null with 'N/A') |
| [Empty](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md#empty) | `boolean` | Show nothing in cell (but underlying value remains) |
| [Prefix](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md#prefix) | `string` | Prefix to use before the cell text |
| [Suffix](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md#suffix) | `string` | Suffix to use after the cell text |
| [Trim](https://www.adaptabletools.com/docs/reference/stringformatteroptions.md#trim) | `boolean` | Trims text (both start and end) |
There are no presets available for string columns
**Example: Column Formatting: String Display Formats**
Column Formatting with String Display Formats
- In this example 4 System String Display Formats are provided:
- `Name` is **uppercase**
- `Language` is given a **Prefix** of 'Lang-'
- `Description` is set to **Content** of "[Too long to show...]" - using Condition (leveraging the `LEN` [AdapTableQL Expression Function](https://www.adaptabletools.com/docs/adaptable-ql-expression-functions/index.md)) that cell value is over 100 characters
- `License` shows as **Empty** - using Condition where Cell Value was 'Other'
### Expand to see the String Display Formats
```ts
FormatColumn: {
FormatColumns: [
{
Name: 'FormatColumn-name-105',
Scope: {
ColumnIds: ['name'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
Trim: false,
},
},
},
{
Name: 'FormatColumn-language-106',
Scope: {
ColumnIds: ['language'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Prefix: 'Lang: ',
},
},
},
{
Name: 'FormatColumn-topics-107',
Scope: {
ColumnIds: ['topics'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Content: '[Too many to list]',
},
},
Rule: {
BooleanExpression: 'LEN([topics] ) > 100',
},
},
{
Name: 'FormatColumn-license-108',
Scope: {
ColumnIds: ['license'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Empty: true,
},
},
Rule: {
Predicates: [
{
PredicateId: 'Is',
Inputs: ['Other'],
},
],
},
},
],
},
```
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'String Display Formats',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'description',
'license',
'created_at',
'updated_at',
'week_issue_change',
'github_stars',
'closed_pr_count',
],
ColumnSorts: [
{
ColumnId: 'week_issue_change',
SortOrder: 'Asc',
},
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Scope: {
ColumnIds: ['name'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
Trim: false,
},
},
},
{
Name: 'formatColumn-language',
Scope: {
ColumnIds: ['language'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Prefix: 'Lang: ',
},
},
},
{
Name: 'formatColumn-description',
Scope: {
ColumnIds: ['description'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Content: '[Too long to show...]',
},
},
Rule: {
BooleanExpression: 'LEN([description]) > 75',
},
},
{
Name: 'formatColumn-license',
Scope: {
ColumnIds: ['license'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Empty: true,
},
},
Rule: {
Predicates: [
{
PredicateId: 'Is',
Inputs: ['Other'],
},
],
},
},
],
},
},
};
```
---
# Display Format using Templates
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-template
- AdapTable enables Display Formats to be created with Template Literals
- These are then dynamically converted using string interpolation
Developers and runtime users can leverage Template Literals when providing a Display Format.
- Template Literals are supplied as part of the Format Column definition
- They are placed in the `Content` property in `Options` property of `DisplayFormat` object
When the cell is rendered the Template Literal is evaluated using string interpolation and the derived substitute text is displayed
Template Literals can be used when providing [String Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-string/index.md) and [Number Display Formats](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md)
## Template Literal Properties
There are 3 Display Format Template Literals available:
| Template Literal | Displays |
| ---------------- | -------------------------------------------- |
| `[column]` | Friendly Name of Formatted Column |
| `[value]` | Non-formatted value for the Cell |
| `[rowData.x]` | Other values in Row (e.g. `[rowData.price]`) |
**Example: Column Formatting: Template Literal Display Formats**
Column Formatting with Placholder Display Formats
- This example shows 2 columns with Display Formats that contain Template Literals:
- `Name` also contains the value of the `language` data value in the row
- `GitHub Stars` adds the word 'Stars' after the value
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Template Display Formats',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'license',
'github_stars',
'github_watchers',
'week_issue_change',
'created_at',
'updated_at',
'closed_pr_count',
'description',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'formatColumn-name',
Scope: {
ColumnIds: ['name'],
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Content: '[value] ([rowData.language])',
},
},
},
{
Name: 'formatColumn-github_stars',
Scope: {
ColumnIds: ['github_stars'],
},
DisplayFormat: {
Formatter: 'NumberFormatter',
Options: {
Content: '[value] Stars',
},
},
},
],
},
},
};
```
---
# Styling Column Headers
Canonical page: https://www.adaptabletools.com/docs/handbook-column-formatting-headers
- It is possible to style and format Column Headers
- This can be done using a Condition if required
Format Column Styles and Display Formats can also be applied to Column Headers.
You **cannot apply** [Conditional Styles](https://www.adaptabletools.com/docs/handbook-column-formatting-conditions/index.md) to Column Headers (as there is only one value and nothing to evaluate)
This is done through the `Target` property of the FormatColumn object which can be either:
- `cell` (the default) - applies the Format just to the Column's data cells
- `columnHeader` - applies the Format only to the Column Header
- All Column Headers **always** only use a [String Display Format](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-string/index.md) (as the Column Header value is a string)
- This applies also to Numeric and Date columns (whose cells use [Number](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-number/index.md) and
[Date](https://www.adaptabletools.com/docs/handbook-column-formatting-display-format-date/index.md) Display Formats respectively)
**Example: Styling & Formatting Column Headers**
Formatting and Styling Column Headers
- This example contains 3 Format Column Styles which have been applied to Column Headers only:
- `All` Columns are centre-aligned
- `Language` Column is blue, capitalised and italicised
- `Numeric` Columns have a distinctive background
```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Formatting Column Headers',
initialState: {
Dashboard: {
ModuleButtons: ['FormatColumn', 'SettingsPanel'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
Name: 'Standard Layout',
TableColumns: [
'name',
'language',
'license',
'github_stars',
'closed_issues_count',
'created_at',
'closed_pr_count',
'updated_at',
'week_issue_change',
'github_watchers',
],
AutoSizeColumns: true,
},
],
},
FormatColumn: {
FormatColumns: [
{
Name: 'style-all',
Scope: {
All: true,
},
Style: {
Alignment: 'Center',
},
Target: 'columnHeader',
},
{
Name: 'formatColumn-number',
Scope: {
DataTypes: ['number'],
},
Style: {
BackColor: '#ffffe0',
ForeColor: 'Brown',
},
Target: 'columnHeader',
},
{
Name: 'formatColumn-language',
Scope: {
ColumnIds: ['language'],
},
Style: {
ForeColor: 'LightBlue',
FontWeight: 'Bold',
FontStyle: 'Italic',
Alignment: 'Center',
},
DisplayFormat: {
Formatter: 'StringFormatter',
Options: {
Case: 'Upper',
},
},
Target: 'columnHeader',
},
],
},
},
};
```
## Conditions
---
# Sharing Comments
Canonical page: https://www.adaptabletools.com/docs/handbook-comments
- Comments are cell-level annotations designed with collaboration in mind
- Users can see each other's Comments and add to the Comment Thread
- The Comment Thread is persisted (via developer provided functions) so that all users can access them
Comments are **annotations** that are attached to individual **Cells** in AG Grid.
They are stored remotely, rather than with the Grid’s underlying data source, and are designed with collaboration in mind.
- Comments differ to [Notes](https://www.adaptabletools.com/docs/handbook-notes/index.md) as they enable inter-colleague communication, while Notes are for personal use
- Comments differ to [Free Text Columns](https://www.adaptabletools.com/docs/handbook-freetext-column/index.md) as they are attached to a single cell rather than form a new Column
Multiple users can add Comments to the same Comment Thread, and all the Comments are visible to all users.
Comments are **not** available if you are using an [auto-generated Primary Key](https://www.adaptabletools.com/docs/getting-started-primary-key/index.md#auto-generated-key)
**Example: Comments in AdapTable**
Using Comments
- This example allows you to simulate 2 users - Alice and Bob - each adding Comments
- Each user can see the Comments created by their colleague, but can only edit their own Comments
```ts
import {
AdaptableContextMenuItemName,
AdaptableOptions,
AdaptableSystemContextMenuItem,
CommentLoadContext,
CommentThread,
CustomContextMenuContext,
InitialState,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
const COMMENTS_PERSISTENCE_KEY = 'docs-demo-comments';
export class CommentsService {
channel = new BroadcastChannel('comments');
constructor() {}
subscribeToComments(callback: (comments: CommentThread[]) => void) {
console.log('subscribing to comments');
this.channel.onmessage = event => {
callback(event.data);
};
}
setComments(comments: CommentThread[]) {
console.log('sending comments', comments);
localStorage.setItem(COMMENTS_PERSISTENCE_KEY, JSON.stringify(comments));
this.channel.postMessage(comments);
}
getComments(): CommentThread[] {
console.log('getting comments');
const commentsString = localStorage.getItem(COMMENTS_PERSISTENCE_KEY);
return commentsString ? JSON.parse(commentsString) : [];
}
clearComments() {
console.log('clearing comments');
localStorage.setItem(COMMENTS_PERSISTENCE_KEY, JSON.stringify([]));
this.channel.postMessage([]);
}
}
const commentsService = new CommentsService();
export const getAdaptableOptionsForUser = (
userName: 'Alice' | 'Bob',
updateCurrentUser: (userName: 'Alice' | 'Bob') => void
): AdaptableOptions => {
const commonInitialState: InitialState = {
Dashboard: {
ModuleButtons: ['Comment'],
PinnedToolbars: ['CurrentUser'],
},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'language',
'github_stars',
'license',
'has_projects',
'has_pages',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'github_watchers',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
};
const userSpecificInitialState =
userName === 'Alice'
? {
Theme: {
CurrentTheme: 'light',
},
}
: // Bob
{
Theme: {
CurrentTheme: 'dark',
},
};
const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Comments',
adaptableStateKey: `DocsCommentsDemo_${userName}`,
userName: userName,
contextMenuOptions: {
customContextMenu: (customMenuContext: CustomContextMenuContext) => {
return customMenuContext.defaultAdaptableMenuStructure
.filter(
(
item
): item is AdaptableSystemContextMenuItem =>
item !== '-'
)
.filter(item => item.category === 'Comment');
},
},
commentOptions: {
loadCommentThreads: async (commentLoadContext: CommentLoadContext) => {
commentsService.subscribeToComments(comments => {
commentLoadContext.adaptableApi.commentApi.setComments(comments);
});
return commentsService.getComments();
},
persistCommentThreads: async (commentThreads: CommentThread[]) => {
commentsService.setComments(commentThreads);
},
},
dashboardOptions: {
customToolbars: [
{
name: 'CurrentUser',
title: 'Current User',
toolbarButtons: [
{
label: 'Alice',
buttonStyle: () => {
return {
tone: userName === 'Alice' ? 'success' : 'neutral',
variant: userName === 'Alice' ? 'raised' : 'outlined',
};
},
onClick: () => {
updateCurrentUser('Alice');
},
},
{
label: 'Bob',
buttonStyle: () => {
return {
tone: userName === 'Bob' ? 'success' : 'neutral',
variant: userName === 'Bob' ? 'raised' : 'outlined',
};
},
onClick: () => {
updateCurrentUser('Bob');
},
},
],
},
],
customDashboardButtons: [
{
tooltip: 'Reset state',
icon: {
name: 'refresh',
},
buttonStyle: {
tone: 'error',
},
onClick: (_, context) => {
localStorage.removeItem(COMMENTS_PERSISTENCE_KEY);
['Alice', 'Bob'].forEach(user => {
localStorage.removeItem(`DocsCommentsDemo_${user}`);
});
context.adaptableApi.stateApi.reloadInitialState();
},
},
],
},
initialState: {
...commonInitialState,
...userSpecificInitialState,
},
};
return adaptableOptions;
};
```
```ts
import {
Adaptable,
AdaptableApi,
AdaptableOptions,
AdaptableReadyInfo,
} from '@adaptabletools/adaptable';
import '@adaptabletools/adaptable/index.css';
import './styles.css';
import {gridOptions} from 'gridOptions';
import {onAdaptableReady} from 'onAdaptableReady';
import {agGridModules} from 'agGridModules';
import {getAdaptableOptionsForUser} from './adaptableOptions';
import {WebFramework} from 'rowData';
let currentAdaptableInstance: AdaptableApi | undefined;
let currentUser: 'Alice' | 'Bob' = 'Alice';
function updateCurrentUser(userName: 'Alice' | 'Bob') {
currentUser = userName;
initializeAdaptable(currentUser);
}
async function initializeAdaptable(userName: 'Alice' | 'Bob') {
// destroy the previous instance (if existing)
if (currentAdaptableInstance) {
const config: any = {
unmount: true,
destroyApi: true,
};
currentAdaptableInstance.destroy(config);
}
currentAdaptableInstance = await Adaptable.init(
{
...getAdaptableOptionsForUser(userName, updateCurrentUser),
} as AdaptableOptions,
{gridOptions: {...gridOptions}, modules: agGridModules}
);
currentAdaptableInstance.eventApi.on(
'AdaptableReady',
(readyInfo: AdaptableReadyInfo) => {
onAdaptableReady(readyInfo);
}
);
}
initializeAdaptable(currentUser);
```
```ts
import * as React from 'react';
import {useState} from 'react';
import {
Adaptable,
AdaptableApi,
AdaptableReadyInfo,
} from '@adaptabletools/adaptable-react-aggrid';
// import adaptable css
import '@adaptabletools/adaptable-react-aggrid/index.css';
// import aggrid themes (using Balham theme)
import './styles.css';
import {onAdaptableReady} from 'onAdaptableReady';
import {gridOptions} from 'gridOptions';
import {agGridModules} from 'agGridModules';
import {getAdaptableOptionsForUser} from './adaptableOptions';
const Grid = ({
currentUser,
onCurrentUserChange,
}: {
currentUser: 'Alice' | 'Bob';
onCurrentUserChange: (userName: 'Alice' | 'Bob') => void;
}) => {
const adaptableApiRef = React.useRef(null);
const adaptableOptions = getAdaptableOptionsForUser(
currentUser,
onCurrentUserChange
);
const agGridOptions = {...gridOptions};
return (
{
// save a reference to adaptable api
adaptableApiRef.current = adaptableReadyInfo.adaptableApi;
onAdaptableReady(adaptableReadyInfo);
}}>
);
};
const App: React.FunctionComponent = () => {
const [currentUser, setCurrentUser] = useState<'Alice' | 'Bob'>('Alice');
return (
setCurrentUser(userName)}
/>
);
};
export default App;
```
```ts
import {ChangeDetectorRef, Component, Inject} from '@angular/core';
import {AdaptableReadyInfo, AdaptableOptions} from '@adaptabletools/adaptable';
import {GridOptions} from 'ag-grid-enterprise';
// Adaptable styles
import '@adaptabletools/adaptable-angular-aggrid/index.css';
// AG Grid styles
import './styles.css';
// grid configuration
import {gridOptions} from 'gridOptions';
import {agGridModules} from 'agGridModules';
import {onAdaptableReady} from 'onAdaptableReady';
import {getAdaptableOptionsForUser} from './adaptableOptions';
import {WebFramework} from 'rowData';
@Component({
selector: 'app-root',
template: `
`,
styles: [
`
:host {
height: 100vh;
display: flex;
flex-flow: column;
}
`,
],
})
export class AppComponent {
adaptableOpts: AdaptableOptions;
agGridOptions: GridOptions;
modules = agGridModules;
currentUser: 'Alice' | 'Bob';
isUpToDate = true;
constructor(
@Inject(ChangeDetectorRef) private changeDetectorRef: ChangeDetectorRef
) {
this.currentUser = 'Alice';
this.adaptableOpts = getAdaptableOptionsForUser(
this.currentUser,
(user: 'Alice' | 'Bob') => this.setCurrentUser(user)
);
this.agGridOptions = {...gridOptions};
}
setCurrentUser(currentUser: 'Alice' | 'Bob') {
this.isUpToDate = false;
this.changeDetectorRef.detectChanges();
this.currentUser = currentUser;
this.initializeAdaptable();
this.isUpToDate = true;
this.changeDetectorRef.detectChanges();
}
initializeAdaptable() {
this.adaptableOpts = getAdaptableOptionsForUser(
this.currentUser,
(user: 'Alice' | 'Bob') => this.setCurrentUser(user)
);
this.agGridOptions = {...gridOptions};
}
adaptableReady($event: AdaptableReadyInfo) {
onAdaptableReady($event);
}
}
```
```ts
```
## Comment Threads
Comments are designed to be written at run-time, and to be used in a collaborative manner.
This is achieved by creating a **Comment Thread** for each cell that contains a Comment, to which all permissioned Team Members can contribute.
### Comment Thread Workflow
The steps to create and collaborate on a Comment Thread are as follows:
If Comments are enabled, every cell will include an *Add Comment* [Context Menu Item](https://www.adaptabletools.com/docs/ui-context-menu/index.md).
Use the `isCellCommentable` property in [Comment Options](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md) to [configure which cells can show Comments](https://www.adaptabletools.com/docs/handbook-comments-configuring/index.md)
Run-time users can write a new Comment by right-clicking on the desired cell, selecting *Add Comment* from the [Context Menu](https://www.adaptabletools.com/docs/ui-context-menu/index.md) and then adding the required text.
This will automatically create a new **Comment Thread** in which the Commment above has been added with the correct User and Timestamp appended.
This Comment Thread will now be available to all members of the Team to add their own Comments.
Only the Author of a Comment can edit or delete it
Other team members can now add their own Comments to the Comment Thread, which will in turn also be viewable to everyone else.
The Comment page in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md) displays all the current Comment Threads and all the Comments they contain.
Users can click on any Comment Thread in that page to open the Comment Thread in the Grid.
## UI Entitlements
The UI Entitlements behaviour for Comments is as expected for `Full` and `Hidden` [`Access Levels`](https://www.adaptabletools.com/docs/reference/accesslevel.md).
The `ReadOnly` Entitlement behaviour is that existing Comments - either previously created or provided by other users are visible - but new Comments cannot be added.
---
# Configuring Comments
Canonical page: https://www.adaptabletools.com/docs/handbook-comments-configuring
- Developers can configure which Cells in the Grid are able to receive Comments
- And like everything in AdapTable, Comments can be easily themed using CSS Variables
Comments are not available or enabled by default in AdapTable.
Instead, they need to be explicitly enabled and set up by developers at design time.
Comments uses a very similar loading and persisting pattern as [Team Sharing](https://www.adaptabletools.com/docs/handbook-team-sharing-configuring/index.md)
### Setting up Comments
There are 3 steps you **must** follow in order for Comments to be available to end users:
Check the Comment Entitlement is one of these Access Levels:
- `Full` (preferable)
- `ReadOnly`
Alternatively, check the `defaultAccessLevel` property is set to *Full*
```tsx {6,7}
const adaptableOptions: AdaptableOptions = {
entitlementOptions: {
defaultAccessLevel: 'Hidden',
moduleEntitlements: [
{
adaptableModule: 'Comment',
accessLevel: 'Full',
},
],
},
};
```
Comments will not appear if the `defaultAccessLevel` property is set to *Hidden* and the Comments Entitlement is not explicitly overridden
Supply async `loadCommentThreads` property in [Comment Options](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md).
This retrieves any saved Comment Threads from the remote storage location.
```tsx {4}
const adaptableOptions: AdaptableOptions = {
commentOptions: {
loadCommentThreads: async (context: CommentLoadContext) => {
commentsService.subscribeToComments(comments => {
context.adaptableApi.commentApi.setComments(comments);
});
return commentsService.getComments();
},
},
};
```
Supply async `persistCommentThreads` property in [Comment Options](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md).
This perists Comment Threads to the remote storage location.
```tsx {4}
const adaptableOptions: AdaptableOptions = {
commentOptions: {
persistCommentThreads: async (commentThreads: CommentThread[]) => {
commentsService.setComments(commentThreads);
},
},
};
```
## Commentable Cells
By default all cells in AG Grid - even readonly ones - can receive a Comment.
But developers are able to use the `isCellCommentable` property in [Comment Options](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md) to specify on a cell by cell basis whether or not a Comment can be added.
**Example: Configuring Commentable Cells**
Setting which Cells can display Comments
- This example contains an implementation for the `isCellCommentable` property in [Comment Options](https://www.adaptabletools.com/docs/handbook-comments-technical-reference/index.md) which prevents Comments from being added to Cells in 2 use cases:
- in the `Language` Column
- in Rows where the value in the `License` Column is "Other"
```ts
import {
CommentableCellContext,
CommentLoadContext,
CommentThread,
CustomContextMenuContext,
AdaptableOptions,
AdaptableSystemContextMenuItem,
AdaptableContextMenuItemName,
} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
const COMMENTS_PERSISTENCE_KEY = 'docs-commentable-cell-comments';
export class CommentsService {
channel = new BroadcastChannel('comments');
constructor() {}
subscribeToComments(callback: (comments: CommentThread[]) => void) {
console.log('subscribing to comments');
this.channel.onmessage = event => {
callback(event.data);
};
}
setComments(comments: CommentThread[]) {
console.log('sending comments', comments);
localStorage.setItem(COMMENTS_PERSISTENCE_KEY, JSON.stringify(comments));
this.channel.postMessage(comments);
}
getComments(): CommentThread[] {
console.log('getting comments');
const commentsString = localStorage.getItem(COMMENTS_PERSISTENCE_KEY);
return commentsString ? JSON.parse(commentsString) : [];
}
}
const commentsService = new CommentsService();
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Commentable Cells',
userName: 'Demo User',
contextMenuOptions: {
customContextMenu: (customMenuContext: CustomContextMenuContext) => {
if (
customMenuContext.gridCell.column.columnId === 'language' ||
customMenuContext.gridCell.rowNode.data['license'] === 'Other'
) {
return customMenuContext.defaultAdaptableMenuStructure;
}
return customMenuContext.defaultAdaptableMenuStructure
.filter(
(
item
): item is AdaptableSystemContextMenuItem =>
item !== '-'
)
.filter(item => item.category === 'Comment');
},
},
commentOptions: {
loadCommentThreads: async (commentLoadContext: CommentLoadContext) => {
commentsService.subscribeToComments(comments => {
commentLoadContext.adaptableApi.commentApi.setComments(comments);
});
return commentsService.getComments();
},
persistCommentThreads: async (commentThreads: CommentThread[]) => {
commentsService.setComments(commentThreads);
},
isCellCommentable: (context: CommentableCellContext) => {
// Dont allow Comments on the Language Column or Rows where License is 'Other'
if (
context.gridCell.column.columnId === 'language' ||
context.gridCell.rowNode.data['license'] === 'Other'
) {
return false;
}
return true;
},
},
dashboardOptions: {
customDashboardButtons: [
{
tooltip: 'Reset state',
icon: {
name: 'refresh',
},
buttonStyle: {
tone: 'error',
},
onClick: (_, context) => {
localStorage.removeItem(COMMENTS_PERSISTENCE_KEY);
context.adaptableApi.stateApi.reloadInitialState();
},
},
],
},
initialState: {
Dashboard: {
ModuleButtons: ['Comment'],
},
Theme: {CurrentTheme: 'dark'},
Layout: {
CurrentLayout: 'Standard Layout',
Layouts: [
{
TableColumns: [
'name',
'github_stars',
'license',
'github_watchers',
'language',
'open_issues_count',
'closed_issues_count',
'created_at',
'has_wiki',
'updated_at',
'pushed_at',
'description',
'open_pr_count',
'closed_pr_count',
'has_projects',
'has_pages',
'week_issue_change',
],
Name: 'Standard Layout',
AutoSizeColumns: true,
},
],
},
},
};
```
## Theming Comments
By default the triangle in a cell to denote a Comment is painted blue.
Technically AdapTable uses the value of the `--ab-color-info` variable, which itself can be overridden
However, like everything [theming-related](https://www.adaptabletools.com/docs/handbook-theming/index.md) in AdapTable, this can be overridden using [CSS Variables](https://www.adaptabletools.com/docs/handbook-theming-custom/index.md).
All that is required is to provide a different value for the `--ab-CellComment-triangle-color` CSS variable.
**Example: Comments CSS**
Configuring Comments using CSS variables
- In this demo we have overridden the `--ab-CellComment-triangle-color` CSS Variable so that the Notes triangle appears as yellow
### Expand to see the CSS provided
```css
:root.ab--theme-dark {
--ab-CellComment-triangle-color: yellow;
}
```
```ts
import {
AdaptableContextMenuItemName,
AdaptableSystemContextMenuItem,
CommentLoadContext,
CommentThread,
CustomContextMenuContext,
} from '@adaptabletools/adaptable';
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from 'rowData';
const COMMENTS_PERSISTENCE_KEY = 'adaptable-css-comments';
export class CommentsService {
channel = new BroadcastChannel('comments');
constructor() {}
subscribeToComments(callback: (comments: CommentThread[]) => void) {
console.log('subscribing to comments');
this.channel.onmessage = event => {
callback(event.data);
};
}
setComments(comments: CommentThread[]) {
console.log('sending comments', comments);
localStorage.setItem(COMMENTS_PERSISTENCE_KEY, JSON.stringify(comments));
this.channel.postMessage(comments);
}
getComments(): CommentThread[] {
console.log('getting comments');
const commentsString = localStorage.getItem(COMMENTS_PERSISTENCE_KEY);
return commentsString ? JSON.parse(commentsString) : [];
}
}
const commentsService = new CommentsService();
export const adaptableOptions: AdaptableOptions = {
primaryKey: 'id',
adaptableId: 'Comments CSS',
userName: 'Demo User',
contextMenuOptions: {
customContextMenu: (customMenuContext: CustomContextMenuContext) => {
return customMenuContext.defaultAdaptableMenuStructure
.filter(
(
item
): item is AdaptableSystemContextMenuItem